【问题标题】:Why LinkedList in Java is not a real Linked List?为什么 Java 中的 LinkedList 不是真正的 Linked List?
【发布时间】:2013-01-26 20:06:21
【问题描述】:

根据定义,链表是一个链表,它的每个元素都指向下一个元素(如果我们谈论的是双链表,则是前一个元素。) http://en.wikipedia.org/wiki/Linked_list

然而,在 Java 中 LinkedList 正在实现 List、Queue、Deque 等。 http://docs.oracle.com/javase/6/docs/api/java/util/LinkedList.html

您无法在 LinkedList 中找到可以在列表中为您提供下一个或上一个对象的方法,您能做的最好的事情就是获取一个迭代器并获取对象。我的问题是为什么 Java 将这种数据结构称为 LinkedList,而它并不是真正的链表?链表可以在 Java 中这样实现:

Public class MyLinkedList{
 public int value;
 public MyLinkedList next;
}

【问题讨论】:

    标签: java linked-list


    【解决方案1】:

    您在 LinkedList 中找不到提供列表中下一个或上一个对象的方法

    不,这是完全合适的。 “列表中的下一项”的想法在列表中没有意义。对于列表中的 node 来说,这是非常有意义的,但这不是 Java API 所公开的。当然,它存在于内部 - 只是没有暴露。如果要遍历列表,请使用迭代器。您仍然可以在开头或结尾添加,从开头或结尾删除,以及从迭代器中添加/删除。

    虽然您确实可以像您建议的示例代码那样将“节点”和“列表”的概念混为一谈,但我认为这通常不是一个好主意。

    换一种说法:你试图达到什么导致你出现问题?我相信你应该能够使用公共 API 做你想做的事——你可能没有注意到这一切。

    【讨论】:

      【解决方案2】:

      我的问题是,为什么 Java 将这种数据结构称为 LinkedList,而它并不是真正的链表?

      因为它的实现是一个链表。来自the documentation

      ListDeque 接口的双向链表实现。实现所有可选列表操作,并允许所有元素(包括null)。

      LinkedList 是一个通过链表实现的ListArrayList 是一个使用数组实现的List,等等。您选择哪一个取决于运行时特性。例如,来自LinkedList 文档:

      所有操作都按照双向链表的预期执行。索引到列表中的操作将从开头或结尾遍历列表,以更接近指定索引的为准。

      所以你知道,例如,你从iteratorlistIterator 获得的Iterator 上的next 将非常有效,但按索引的get 将涉及遍历。

      【讨论】:

      • 哦,你的意思是LinkedList的实现是一个链表,但是在你使用LinkeList的时候它没有提供链表功能?
      • @sheidaei:我认为确实如此,通过IteratorListIterator,并且您知道(从文档中)底层结构实现了使用双重链接的结构列表,因此nextprevious 将非常有效。
      • 不同的算法需要将链表节点存储在缓存中,以便可以轻松删除或更新它们。例如LRU 缓存算法。 Java 没有向客户端公开链表节点的概念。这会阻止客户端有效地实现这些算法。也许换一种问法,如何实现需要缓存链表节点以支持在该双向链接节点之前/之后的 o(1) 插入/删除的算法
      【解决方案3】:

      集合是链表还是数组列表与它的约定无关,而与它的实现有关。 LinkedList 在实现上确实是一个链表,在契约上是一个java.util.List

      它展示的不是它的 API,而是它的空间/时间复杂性特征,任何熟悉链表的人都可以轻松预测。

      作为参考,这是LinkedList节点的实际实现,非常符合您的期望:

      957 private static class 节点 {
      958 E item;
      959 Node next;
      960 Node prev;
      962 Node(Node prev, E element, Node next) {
      963 this.item = element;
      964 this.next = next;
      965 this.prev = prev;
      966 }
      967 }

      【讨论】:

        【解决方案4】:

        在阅读您的问题时,我感觉您没有很好地区分链表的概念和链表的实现。

        您的示例代码很好地展示了链表的概念,但这并不意味着它是实现链表的唯一方法或最佳方法。我相信您可以使用内置的LinkedList 类执行标准链表所需的任何操作,尽管您可能会在数据结构类或教科书中看到一组不熟悉的 API。

        所以基本上就是一个链表,只要能做到O(1)时间的插入操作,O(1)时间的删除操作,O(n)时间的搜索操作等等,对比时间复杂度其他数据结构,如数组。

        内置的LinkedList 没有直接提供next 操作,而是通过它的迭代器。这只是 Java 语言的设计决定,因为您可能会从 Iterator pattern 中受益。

        而Java是典型的面向对象语言,其主要特点之一是Abstraction

        【讨论】:

          【解决方案5】:

          除了其他人的正确答案外,如果接口的底层实现是一个链表,实现对象将有一个方法来获取链表中的下一项。该方法只是没有作为合同的一部分公开。

          实现是链表这一事实会影响 List 合约的各种方法的 Big-O 性能。

          【讨论】:

            【解决方案6】:

            然而,在 Java 中 LinkedList 正在实现 List、Queue、Deque 等。

            根据 API,LinkedList 实现了这些接口,因此可以使用任何这些结构。

            【讨论】:

              【解决方案7】:

              所以我不知道@Marko 从哪里读取该实现,但 1.8 jdk 中的实现大不相同。

              首先,声明的第一个变量是:

               transient int size = 0;
              

              每当一个节点被添加到列表中时,该值就会增加。这意味着列表中存在 Integer.MAX_VALUE (2147483647) 节点的固有限制。在现代世界,这个数字并不像看起来那么大。问题不在于我们没有真正的链表(创建它们很简单),但对于所有 3rd 方库,他们很可能不会考虑到这一点,然后整个库就会被淘汰.

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-08-05
                • 2011-08-24
                • 2011-04-11
                • 1970-01-01
                • 1970-01-01
                • 2013-04-10
                • 2015-07-30
                相关资源
                最近更新 更多