我对链接列表的时间复杂性感到有些困惑。在本文here中,它指出链接列表中的插入和删除是O(1)。我想知道这是怎么回事?假设前向和下一个指针是已知的吗?那不就是Double Linked List吗?如果有人能澄清这一点,我将不胜感激。以及单个链表的插入/删除的时间复杂度如何是O(1)?
答案 0 :(得分:4)
是否假设前向和下一个指针已知?
在单链表中,对于插入和删除,您需要在插入/删除点之前指向元素。一切顺利。
例如:
# insert y after x in O(1)
def insert_after(x, y):
y.next = x.next
x.next = y
# delete the element after x in O(1)
def delete_after(x):
x.next = x.next.next
对于许多应用程序,很容易通过算法携带您当前正在查看的项目的前身,以允许在恒定时间内动态插入和删除。当然,您总是可以在O(1)中的列表前面插入和删除,这允许类似堆栈(LIFO)的使用模式。
当您只知道指向该项目的指针时,删除项目通常在O(1)中不。 编辑:正如codebeard所示,我们只需知道指向插入/删除点的指针就可以 插入和删除。它涉及从后继者复制数据,从而避免修复前一个的next
指针。
答案 1 :(得分:3)
是的,假设您已经知道要插入数据的位置。
假设您在列表中有一些项目p
,并且您希望在列表中new
之后插入新元素p
:
new->next = p->next;
p->next = new;
或者,假设您要在 new
之前插入p
。这仍然可以在O(1)时间内完成:
if (p == head) {
new->next = head;
head = new;
} else {
tmp = p->data;
p->data = new->data;
new->data = tmp;
new->next = p->next;
p->next = new;
}
至于删除传统单链表中的项目,严格来说不是O(1)!
删除 last 元素以外的任何元素是O(1)。如果你试图删除单链表中的最后一个元素,你需要知道它之前的元素(假设你之前不知道它需要O(N)时间)。
删除项目p
:
free_if_necessary(p->data);
if (p->next) {
/* O(1) */
nextnext = p->next->next;
nextdata = p->next->data;
destroy_if_necessary(p->next);
p->data = nextdata;
p->next = nextnext;
} else if (p == head) {
destroy_if_necessary(p);
head = NULL;
} else {
/* O(n) */
prev = find_prev(head, p);
destroy_if_necessary(p);
prev->next = NULL;
}
答案 2 :(得分:0)
这可能与数组的删除和插入操作有关。
前提条件是您知道插入或删除的位置。
在数组中,如果要在位置pos
处插入或删除元素,则应将其他元素移到位置pos
之后,因此复杂度为O(N)
。
但在List中,当您执行相同的操作时,您不需要考虑其他元素,因此复杂度为O(1)
。