【发布时间】:2014-05-07 11:27:20
【问题描述】:
标准的链表实现是双向链接的。因此我们分别有一个headNode和一个tailNode。我已经阅读了 getValue(int n),作为返回保存在列表中第 n 个元素的数据部分。现在假设我们从 headNode 开始对链表进行顺序搜索,如果位置是链表中的最后一个元素,最坏的情况将是 O(n)。但是,如果我们检查是否 n > size / 2,那么我们就知道是在 headNode 还是在 tailNode 开始遍历。这意味着它将执行 O(n / 2),可以重写为 O(1/2n)。
根据 Big O Notation 的规则,系数无关紧要,因此最坏的情况仍然是 O(n)。我看到了这个逻辑的一个缺陷,因为如果我们有一个包含大量节点的列表,比如 100 万个,那么最坏的情况是 500,000 比最坏的情况 1,000,000 好得多。最坏的情况是如果我们正在搜索的位置实际上是 size / 2。我已经实现了这段代码,发现当通过的位置小于 size / 2 时,它们以相同的速度执行,但是,当通过的位置大于 size / 2,它的执行速度明显更快。我的问题是,当这样一个简单的解决方案将最坏的情况减半时,我们怎么能说这是 O(n)。显然,系数很重要,我看不出我们如何得出它们无关紧要的结论。代码如下:
//This is headed by firstNode and tailed by lastNode
public Node getValue(int position)
{
if (!isEmpty() && position <= size)
{
if (position > (size / 2))
return traverseReverse(position);
else
return sequentialSearch(position);
}
return null;
}
private Node traverseReverse(int searchIndex)
{
Node currentNode = lastNode;
int position = size;
while (currentNode != null)
{
if (position == searchIndex)
return currentNode;
position--;
currentNode = currentNode.previous;
}
return null;
}
private Node sequentialSearch(int position)
{
Node currentNode = firstNode;
int n = 0;
while (currentNode != null)
{
if (n == position)
return currentNode;
n++;
currentNode = currentNode.next;
}
return null;
}
【问题讨论】:
-
这个问题似乎是题外话,因为它是关于计算机科学中的通用概念而不是编程。考虑在Computer Science.SE 上问这个问题
-
复杂性不等于性能。它描述了算法的渐近行为,这意味着随着 N 的增加,它将如何表现,这在这里显然是线性的。
-
无论如何请记住,O 表示法用于表示渐近复杂性。这意味着您应该只考虑 big
n。以n = 10^50为例,在这样的列表中搜索一个元素需要数十亿年的时间。以n = 10^50/2为例,它仍然需要数十亿年的时间来搜索元素,从实际的角度来看并没有真正改变。然而,在10^50元素向量中进行二等分搜索,现在大约需要50 * log2(10)操作才能找到元素,这是瞬时。 那就是大哦想要处理的事情。 -
是的,这个问题听起来像是个误会。对于非常大的 n,执行时间与 N 成正比增长。例如,与 O(nn) 相比,O(n) 非常接近 O(n/2)。与 O(nn/2) 相比,O(n/2) 也是如此。由于我们正在研究运行时根据 N 扩展的方式,因此常数因子确实足够小,以至于在比较此类术语时,您可以忽略较大的 n。
-
另一种看待大 O 的方式是,您可以对 O(N) 算法进行所有您想要的性能改进,但只要生成的算法仍然是 O(N),它'对于足够高的 N 值,它仍然比任何 O(log N) 算法都要慢。这几乎是算法中大 O 的实际目的。
标签: java performance algorithm doubly-linked-list