为什么双向链表中节点删除的时间复杂度(O(1))比单向链表中的节点删除时间复杂度(O(n))更快呢?
该问题假设已知要删除的节点并可用指向该节点的指针。
为了删除一个节点并将前一个节点和后一个节点连接起来,需要知道它们的指针。在双向链表中,这两个指针都在要删除的节点中可用。此时时间复杂度是常数级别,即O(1)。
而在单向链表中,先前节点的指针是未知的并且只能通过从头开始遍历列表,直到达到具有指向要删除的节点的下一个节点指针的节点才能找到它。此时时间复杂度为O(n)。
在只知道要删除的节点值的情况下,必须搜索列表,此时在单向和双向链表中时间复杂度都变成了O(n)。
实际上,单链表中的删除操作也可以以O(1)的时间复杂度实现。
假设有一个单链表,其状态如下:
SinglyLinkedList:
Node 1 -> Node 2
Node 2 -> Node 3
Node 3 -> Node 4
Node 4 -> None
Head = Node 1
我们可以这样实现删除节点2
:
Node 2 Value <- Node 3 Value
Node 2 -> Node 4
在这里,我们将Node 2
的值替换为其下一个节点Node 3
的值,并将其下一个指针设置为Node 3
的下一个指针Node 4
,跳过现在有效地“重复”的Node 3
。因此不需要遍历。
在已知位置插入和删除的时间复杂度为O(1)。然而,要找到该位置的时间复杂度为O(n),除非它是列表的头部或尾部。
当我们谈论插入和删除的复杂度时,通常假设我们已经知道将发生的位置。
这与修复在删除节点之前的前一个节点中的下一个指针的复杂性有关。
除非要删除的元素是头(或第一个)节点,否则我们需要遍历到要删除的节点之前的节点。因此,在最坏情况下,即需要删除最后一个节点时,指针必须一直到达倒数第二个节点,从而遍历(n-1)个位置,这给我们带来了O(n)的时间复杂度。
1 -> 2 -> 3 -> 4 -> 5-> 6-> 7-> 8 -> 9 -> 10
4->next = 5->next;
或者
Node* temp = givenNode->prev;
temp->next = givenNode->next;
时间复杂度 = O(1)
Node* temp = head;
while(temp->next != givenNode)
{
temp = temp->next;
}
temp->next = givenNode->next;
如果发生缓存命中
,我们必须将元素移动到列表的前面。如果节点在双向链表的中间某处,由于我们在哈希映射中保持指针并以O(1)时间检索,因此我们可以通过删除它来。
next_temp=retrieved_node.next
prev_temp=retrieved_node.prev
然后将指针设置为None
retrieved_node.next=None
retrieved_node.prev=None
然后你可以重新连接链表中缺失的部分
prev_temp.next=next_temp