Java 如果想要接近尾端的元素,LinkedList是否从末尾开始搜索?

Java 如果想要接近尾端的元素,LinkedList是否从末尾开始搜索?,java,collections,linked-list,Java,Collections,Linked List,我对LinkedList在获取数据时如何搜索数据感兴趣。 例如: 我们有一个包含1000个元素的LinkedList。我想通过索引950获取元素,所以我写list.get 950。java会从一开始就寻找那个元素吗?或者它也有一个指向最后一个元素的指针? 我已经编写了一些小程序来测试它。但它的工作原理是错误的,无论它是什么,第一次得到的时间最长 long time; time = System.nanoTime(); list.get(1); time = System.nanoTime() -

我对LinkedList在获取数据时如何搜索数据感兴趣。 例如: 我们有一个包含1000个元素的LinkedList。我想通过索引950获取元素,所以我写list.get 950。java会从一开始就寻找那个元素吗?或者它也有一个指向最后一个元素的指针? 我已经编写了一些小程序来测试它。但它的工作原理是错误的,无论它是什么,第一次得到的时间最长

long time;
time = System.nanoTime();
list.get(1);
time = System.nanoTime() - time;
System.out.println("For element at the beginning " + time);
time = System.nanoTime();
list.get(999);
time = System.nanoTime() - time;
System.out.println("For element at the end " + time);
根据for LinkedList,它确实有一个指向最后一个节点的指针:

根据for LinkedList,它确实有一个指向最后一个节点的指针:

你能展示一下观察到的时间安排吗?我怀疑它们太接近了,以至于你无法根据它们得出任何结论!? 请参见编写适当的基准测试 您可以简单地检查linkedlist的源代码,看看它是如何搜索的。 LinkedList实际上有一个第一个和最后一个引用,是的,如果索引>=size>>1,它有逻辑从后面搜索索引是否合理接近 你能展示一下观察到的时间安排吗?我怀疑它们太接近了,以至于你无法根据它们得出任何结论!? 请参见编写适当的基准测试 您可以简单地检查linkedlist的源代码,看看它是如何搜索的。 LinkedList实际上有一个第一个和最后一个引用,是的,如果索引>=size>>1,它有逻辑从后面搜索索引是否合理接近
是的,如果元素超过一半,则从后面开始:

Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

是的,如果元素超过一半,则从后面开始:

Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

除了其他答案


你的测试是正确的。在其他答案中检查LinkedListnode源。索引999是列表中的最后一个,所以node方法立即返回最后一个元素。索引1是列表中的第二个,第一个是0,因此当您调用get1时,除了其他答案之外,还有额外的for循环迭代以获取第一个之后的元素。


你的测试是正确的。在其他答案中检查LinkedListnode源。索引999是列表中的最后一个,所以node方法立即返回最后一个元素。索引1是列表中的第二个,第一个是0,因此当您调用get1时,在第一个元素之后还有额外的for循环迭代来获取元素。

并不意味着在执行get时它从尾部开始,尽管它是这样。感谢您的解释!还有例子!这有帮助!这并不意味着它在做get时从尾部开始,尽管它确实如此。谢谢你的解释!还有例子!这有帮助!时间安排太不一样了。第一次总是比第二次大。例如:对于11605 ns开头的元素,对于3755 ns结尾的元素,当我更改调用顺序时:对于11605末尾的元素,对于2048开头的元素,这对我来说毫无意义。你能解释一下为什么吗?时间安排太不一样了。第一次总是比第二次大。例如:对于11605 ns开头的元素,对于3755 ns结尾的元素,当我更改调用顺序时:对于11605末尾的元素,对于2048开头的元素,这对我来说毫无意义。你能解释一下为什么吗?是的。你是对的。我已经将它改为get0,但仍然会得到奇怪的结果。计时太不一样了。第一次总是比第二次大。例如:对于11605 ns开头的元素,对于3755 ns结尾的元素,当我更改调用顺序时:对于11605末尾的元素,对于2048开头的元素,这对我来说毫无意义。你能解释一下为什么会这样吗?这肯定是一些JVM优化。例如,如果列表大小没有改变,就不需要为连续的get调用计算两次大小>>1。嗯,也许我现在明白了。谢谢是 啊你是对的。我已经将它改为get0,但仍然会得到奇怪的结果。计时太不一样了。第一次总是比第二次大。例如:对于11605 ns开头的元素,对于3755 ns结尾的元素,当我更改调用顺序时:对于11605末尾的元素,对于2048开头的元素,这对我来说毫无意义。你能解释一下为什么会这样吗?这肯定是一些JVM优化。例如,如果列表大小没有改变,就不需要为连续的get调用计算两次大小>>1。嗯,也许我现在明白了。谢谢
Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}