Java 链表getValue(int n)应为O(n/2)

Java 链表getValue(int n)应为O(n/2),java,performance,algorithm,doubly-linked-list,Java,Performance,Algorithm,Doubly Linked List,标准的链表实现是双重链接的。因此,我们分别有一个头部节点和一个尾部节点。我已经读取了getValue(intn),作为返回,它包含在第n个元素的列表中的数据部分。现在假设我们从headNode开始对链表进行顺序搜索,如果位置是列表中的最后一个元素,那么最坏的情况是O(n)。然而,如果我们检查n>size/2,那么我们就知道是在headNode还是在tailNode开始遍历。这意味着它将执行O(n/2),可以重写为O(1/2n) 根据大O表示法的规则,系数并不重要,因此最坏的情况仍然是O(n)。我

标准的链表实现是双重链接的。因此,我们分别有一个头部节点和一个尾部节点。我已经读取了getValue(intn),作为返回,它包含在第n个元素的列表中的数据部分。现在假设我们从headNode开始对链表进行顺序搜索,如果位置是列表中的最后一个元素,那么最坏的情况是O(n)。然而,如果我们检查n>size/2,那么我们就知道是在headNode还是在tailNode开始遍历。这意味着它将执行O(n/2),可以重写为O(1/2n)

根据大O表示法的规则,系数并不重要,因此最坏的情况仍然是O(n)。我看到了这个逻辑中的一个缺陷,因为如果我们有一个包含大量节点的列表,比如说100万个,那么最坏的情况是50万个,比最坏的情况是100万个要好得多。最坏的情况是,如果我们正在寻找的职位实际上是大小/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;
}
//它以firstNode开头,以lastNode结尾
公共节点getValue(int位置)
{
如果(!isEmpty()&&position(大小/2))
返回横向(位置);
其他的
返回顺序搜索(位置);
}
返回null;
}
私有节点遍历反向(int searchIndex)
{
节点currentNode=lastNode;
int位置=大小;
while(currentNode!=null)
{
如果(位置==搜索索引)
返回当前节点;
位置--;
currentNode=currentNode.previous;
}
返回null;
}
专用节点顺序搜索(int位置)
{
节点currentNode=firstNode;
int n=0;
while(currentNode!=null)
{
如果(n==位置)
返回当前节点;
n++;
currentNode=currentNode.next;
}
返回null;
}

复杂性和运行时是相关概念,但并不相同。复杂性显示了
n
与运行时之间的关系,因为
n
增加了

无论系数是多少,线性关系都是O(n)。如果您想比较最坏情况下的运行时,一定要这样做,但复杂性分析不是正确的工具。这只是一个起点


无论您是从前面还是后面搜索链接列表,您需要查看的项目的平均数量与其大小成正比。

这个问题似乎离题了,因为它涉及计算机科学中的一般概念,而不是编程。考虑这个问题的复杂性并不等于性能。它描述了一个算法的渐近行为,这意味着当N增加时它将如何表现,这在这里显然是线性的。无论如何,请记住,O符号是用来描述渐近复杂性的。这意味着你应该只考虑大<代码> N< /代码>。以
n=10^50
为例,在这样的列表中搜索一个元素需要数十亿年的时间。以
n=10^50/2
为例,搜索元素仍然需要数十亿年的时间,从实用的角度来看,没有什么真正的变化。然而,在
10^50
元素向量中进行对分搜索,现在需要大约
50*log2(10)
操作才能找到元素,这是瞬时的。这就是big oh想要解决的问题。是的,这个问题闻起来像是个误会。对于非常大的n,执行时间与n成比例增长。例如,与O(nn)相比,O(n)非常接近O(n/2)。与O(nn/2)相比,O(n/2)也是如此。由于我们正在研究运行时根据N进行扩展的方式,常数因子确实很小,当比较这些项时,可以忽略大N的常数因子。另一种看待大O的方式是,可以对O(N)算法进行所有性能改进,但只要得到的算法仍然是O(N),对于足够高的N值,任何O(logn)算法都要慢一些。这几乎就是算法中大O的实际用途。