【问题标题】:Why is accessing an item by index slower in a linked list than an array?为什么在链表中按索引访问项目比数组慢?
【发布时间】:2016-06-11 23:37:04
【问题描述】:

我认为我遗漏了一个非常明显的观点,但在我的 Java 教科书中找不到。

我了解对于链表而言,节点存储在内存中不一定必须是连续的。这是否也意味着链表不可索引?如果是这样,那么在链表中查找项目的唯一方法就是遍历链表,对吧,而您可以通过索引从数组中get

【问题讨论】:

  • 链表访问是(sequential, so) O(n);数组访问是(随机的,所以)O(1)。这篇文章中有很多很好的信息:en.wikipedia.org/wiki/Linked_list
  • 谢谢@BrianSnow。我仍然不明白为什么链表不可索引。从我收集到的信息来看,链表是否不包含对它所包含的所有项目的引用——只有头部和/或尾部?因此不允许通过索引访问?
  • 假设您有一个名为 L 的链表。可能在 L 上公开的唯一操作将是 head(),它返回链表的头部:Node<T> head = L.head()。列表的头部只是一个简单的节点,它也只暴露了一个操作,称为next(),它返回列表中的下一个节点。您现在可以通过执行Node<T> node = head.next() 来遍历列表,直到您到达列表末尾和node.next() == null。所以你是对的:链表不会直接引用它的所有元素——它只保留对其头部的引用。

标签: java


【解决方案1】:

为什么在链表中按索引访问项目比在数组中慢?

链表有一个条目链。如果你想获取(比如说)42 位置的元素,代码必须:

  • 获取第一个元素的入口(位置0
  • 点击next链接到1位置的条目
  • 点击next链接到2职位的条目

等等......总共42次。

没有捷径。

我仍然不明白为什么链表是不可索引的......

现在LinkedList 是可索引的,因为get(int) 操作有效。只是索引LinkedList低效。通常,在长度为N 的链表中执行get(i) 需要O(N) 步骤。与数组或ArrayList 相比,您可以一步检索数据结构的任何元素。我们说复杂度是O(1)

将此与一般的 Set 对象,特别是 HashSet 进行对比。 HashSet 类不可索引,因为没有 get(int) 方法来检索位置 i 处的集合元素。事实上,即使是集合中“位置 i”的概念也是没有意义的。 Set 中元素的顺序未指定,并且(对于某些 Set 实现,例如 HashSet)它可能实际上是不确定的。

【讨论】:

  • 再次,我的问题是,我们可以将索引与链表一起使用吗?
  • 没有什么能阻止你这样做。除了它会之外。此外,我已经回答过:“LinkedList 是可索引的,因为有一个 get(int) 操作有效。”
【解决方案2】:

一些链表实现提供了一种使用索引访问它的元素的方法,但事实是,如果你想获得链表中的第 10 个元素,你的编译器仍然必须遍历从 0 到 9 的所有序列,因为元素可能分布在内存中。另一方面,当您使用索引请求数组中的第 10 个元素时,编译器会计算第 10 个元素的确切位置并直接跳转到该元素。数组和列表有不同的用途;如果您的算法需要在您的数据结构上前后移动,那么使用数组非常有效。如果您主要需要添加/删除操作,那么使用列表是有效的

【讨论】:

    【解决方案3】:

    使用链表,您可以随时添加和删除元素,因此索引它没有任何意义。想象一下,您创建了一个指向列表第三个元素的索引。之后,在列表的开头插入一个新元素。应该返回什么值?

    但是,例如,可以在列表的中间创建一个索引,并且仅当您在列表的后半部分添加或删除元素时才使用它。

    @paxdiablo 这里解释的很好Is there a known implementation of an indexed linked list?

    【讨论】:

    • @paxdiablo 提出的二维链表实现是O(N^0.5)。这很有趣,但在实用中使用 ... 作为 Java 中的通用列表结构有限。考虑到 ArrayListO(1) 并且它比任何通用链表使用 更少 空间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2016-08-31
    相关资源
    最近更新 更多