来自linked-list标签wiki摘录:
链表是元素包含的数据结构 引用下一个(以及可选的前一个)元素。关联 列表提供 O(1)在任何位置插入和删除,O(1)列表 连接,O(1)访问前面(和可选的后面) 位置以及O(1)下一个元素访问。随机访问有O(N) 复杂性通常是未实现的。
(强调我的)
我很惊讶地读到了这一点 - 如何将插入列表放在一个复杂程度低于读取索引的随机索引上?
所以我看了the source code for java.util.LinkedList
。 add(int, E)
method是:
public void add(int index, E element) {
addBefore(element, (index==size ? header : entry(index)));
}
addBefore(E, Entry<E>
method只是指针重新分配,但也有entry(int)
method:
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)时间的情况,当然不是恒定的时间。
我错过了什么?我误解了大O符号吗?
答案 0 :(得分:13)
这是因为您正在阅读的文章将“转到该索引”视为单独的操作。本文假设您已经处于要执行的索引add(int,E)。
总结:
插入或移除操作= O(1)
在n th 指数中查找节点= O(n)
答案 1 :(得分:4)
好吧,它们确实支持在任意位置进行常量插入 - 但只有在碰巧有一个指向列表条目的指针之后或之前要插入的东西。当然,如果您只有索引,这将不起作用,但这不是您在优化代码中通常所做的。
在Java中,您也可以这样做,但only using a list iterator。
与arraylists相比,链接列表的这个属性是它们的最大优势 - 例如,如果你想从聊天室的用户列表中删除用户,你可以在用户列表中存储一个指向用户位置的指针。用户,当他想离开房间时,可以实现O(1)
操作。
答案 2 :(得分:2)
将新节点链接到任何节点的操作是O(1),但查找(有助于循环)相关索引的操作肯定是O( n)中。
没有魔力;)
答案 3 :(得分:1)
您引用的维基页面说:
O(1)在任何位置插入和移除
然后你问:
我很惊讶地看到这个 - 如何在随机索引中插入列表
这就是混乱:术语位置和索引并不是用来表示相同的事情。 wiki讨论迭代器或指针,而不是索引。