Временная сложность удаления узлов в одно- и двусвязных списках

Почему временная сложность удаления узлов в двусвязных списках (O(1)) быстрее, чем удаление узлов в односвязных списках (O(n))?




Ответы (8)


Проблема предполагает, что удаляемый узел известен и доступен указатель на этот узел.

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

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

В тех случаях, когда удаляемый узел известен только по значению, необходимо выполнить поиск в списке, и временная сложность становится равной O (n) как в односвязных, так и в двусвязных списках.

person Raj    schedule 02.05.2013
comment
Это неверно в отношении удаления узла из односвязного списка, требующего сложности O (n) - см. Мой ответ ниже. Существует трюк, когда вы копируете значение из следующего узла из удаляемого, а затем пропускаете его, чтобы впоследствии указать на узел, что устраняет необходимость обхода списка. - person Ben; 07.10.2017

На самом деле удаление в односвязных списках также может быть реализовано в O (1).

Дан односвязный список со следующим состоянием:

SinglyLinkedList:
   Node 1 -> Node 2
   Node 2 -> Node 3
   Node 3 -> Node 4
   Node 4 -> None

   Head = Node 1

Мы можем реализовать delete Node 2 таким образом:

Node 2 Value <- Node 3 Value
Node 2 -> Node 4

Здесь мы заменяем значение Node 2 значением его следующего узла (Node 3) и устанавливаем его указатель следующего значения на следующий указатель значения Node 3 (Node 4), пропуская теперь фактически "дубликат" Node 3. Таким образом, обход не требуется.

person Ben    schedule 07.10.2017
comment
Имеет смысл, но не будет работать при удалении последнего элемента, если у вас нет ссылки на предыдущий (предпоследний) узел. - person peterfields; 23.09.2018
comment
В этом случае @peterfields вы просто полностью удаляете узел, поэтому ссылка на предыдущий узел больше ни на что не указывает. Специфика GC и т. д., очевидно, будет зависеть от технологии и реализации (например, вы можете использовать слабую ссылку). - person Ben; 24.09.2018
comment
прежде чем пытаться что-то заменить, вы должны пройтись по списку и сначала найти удаленный узел. что в основном то же самое, что и при движении по списку, пока не будет найден предшественник удаленного узла. на самом деле ваш путь включает в себя дополнительный шаг вперед, так что это хуже, чем канонический способ O (n) сделать это - person mangusta; 04.02.2019
comment
@mangusta Это неправильно. То, что вы описываете, - это операция поиска, за которой следует операция удаления. Операции удаления уже знают, какой узел должен быть удален. Если вы сомневаетесь в временных сложностях общих структур данных, всегда полезно обратиться к bigochheatsheet.com. - person Ben; 15.02.2019
comment
ну ладно, я не предполагал копировать данные. копирование — слишком затратная операция, если в узле много полей данных. пс. я точно не тот, кому нужна шпаргалка - person mangusta; 15.02.2019
comment
Вам не нужно копировать данные, вы можете иметь ссылку (указатель) на узел, точно так же, как узлы в связанном списке указывают на следующий узел. - person Ben; 16.02.2019

Потому что ты не можешь оглянуться назад...

person Paul    schedule 15.12.2009

Это связано со сложностью исправления следующего указателя в узле, предшествующем удаляемому.

person i_am_jorf    schedule 13.12.2009

Вставка и удаление в известной позиции — O(1). Однако найти эту позицию можно за O(n), если только она не находится в начале или в конце списка.

Когда мы говорим о сложности вставки и удаления, мы обычно предполагаем, что уже знаем, где это произойдет.

person Tony    schedule 17.11.2014

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

person Nilashish Chakraborty    schedule 05.08.2016

Я не думаю, что это O (1), если вы не знаете адрес узла, который должен быть удален ..... Разве вы не зацикливаетесь, чтобы добраться до узла, который должен быть удален из головы ????

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

Но в одном связанном списке вам нужно пройти от головы, чтобы получить его предыдущий и следующий адрес, не имеет значения, есть ли у вас адрес узла, который нужно удалить, или положение узла (например, 1-й, 2-й, 10-й и т. д., .) Быть удаленным .

person srikar sana    schedule 31.03.2019

Предположим, есть связанный список от 1 до 10, и вам нужно удалить узел 5, расположение которого вам дано.

1 -> 2 -> 3 -> 4 -> 5-> 6-> 7-> 8 -> 9 -> 10

Вам нужно будет соединить следующий указатель 4 с 6, чтобы удалить 5.

  1. Двусвязный список. Вы можете использовать предыдущий указатель на 5, чтобы перейти к 4. Затем вы можете сделать
4->next = 5->next;

or

Node* temp = givenNode->prev;
temp->next = givenNode->next;

Временная сложность = O(1)

  1. односвязный список Поскольку у вас нет предыдущего указателя в односвязном списке, вы не можете вернуться назад, поэтому вам придется пройти по списку с головы
Node* temp = head;
while(temp->next != givenNode)
{
  temp = temp->next;
}
temp->next = givenNode->next;

Временная сложность = O (N)

person Naima Farooqi    schedule 20.09.2020