Как LinkedList добавляет (int, E) сложности O (1)?

Из tag wiki excerpt

Связанный список - это структура данных, в которой содержатся элементы ссылки на следующий (и, возможно, предыдущий) элемент. связанный списки предлагают O (1) вставку и удаление в любой позиции, список O (1) конкатенация и O (1) доступ спереди (и, возможно, обратно) а также O (1) доступ к следующему элементу. Случайный доступ имеет O (N) сложность и обычно не реализуется.

(акцент мой)

Я был удивлен, прочитав это & ​​ndash; как список может вставляться в случайный индекс с меньшей сложностью, чем просто читать этот индекс?

Итак, я посмотрел исходный код java.util.LinkedList. Метод add(int, E):

public void add(int index, E element) {
    addBefore(element, (index==size ? header : entry(index)));
}

Метод addBefore(E, Entry<E> - это просто переназначение указателя, но также метод entry(int):

if (index < 0 || index >= size)
        throw new IndexOutOfBoundsException("Index: "+index+
                                            ", Size: "+size);
    Entry<E> e = header;
    if (index < (size >> 1)) {
        for (int i = 0; i <= index; i++)
            e = e.next;
    } else {
        for (int i = size; i > index; i--)
            e = e.previous;
    }
    return e;
}

Даже при оптимизации по половинному размеру цикл for здесь (тот или другой) кажется мне бесполезным, что этот метод (и, следовательно, add(int, E)) работает в минимальном наихудшем сценарии O (n) и, конечно, не постоянное время.

Что мне не хватает? Неужели я неправильно понимаю обозначение Big-O?

Ответы

Ответ 1

Ну, они поддерживают постоянные вставки в произвольных позициях, но , только если, у вас есть указатель на запись списка, после которой или перед которой вы хотите что-то вставить. Конечно, это не сработает, если у вас есть только индекс, но это не то, что вы обычно делаете в оптимизированном коде.

В Java вы тоже можете это сделать, но использовать только итератор списка.

Это свойство связанных списков является их самым большим преимуществом по сравнению с аррайалистами или около того - например, если вы хотите удалить пользователя из списка пользователей чата, вы можете сохранить указатель на позицию пользователя в списке пользователей в пользователь, так что, когда он хочет покинуть комнату, это может быть реализовано как операция O(1).

Ответ 2

Это потому, что статья, которую вы читаете, считается "попаданием в этот индекс" в качестве отдельной операции. В статье предполагается, что вы уже указали индекс, который хотите выполнить add (int, E).

В заключение:

Вставка или удаление операции = O (1)

Поиск node при n th index = O (n)

Ответ 3

Операцией привязки нового node к любому node является O (1), но операция нахождения (помогает в цикле) соответствующий индекс определенно O (n).

Нет волшебства;)

Ответ 4

Процитированная вами страница wiki говорит:

O (1) вставка и удаление в любой позиции

Затем вы спрашиваете:

Я с удивлением прочитал это - как может вставить список в случайный индекс

В этом заключается путаница: положение и индекс терминов не используются, чтобы означать одно и то же. Вики рассказывают об итераторе или указателе, а не об индексе.