繁体   English   中英

加速链表?

[英]Speeding up a linked list?

我是一名学生,对 Java 还很陌生。 我查看了 Java、Linked List 和 ArrayList 中的两个集合实现的不同速度。 我知道 ArrayList 在查找和将值放入其索引时要快得多。 我的问题是:

如果可能的话,如何使链表更快?

谢谢你的帮助。

兹马希尔

在谈论速度时,您可能指的是复杂性 ArrayList (和数组)的插入和检索操作是 O(1),而对于LinkedList它们是 O(n)。 这不能改变——它是“根据定义”的。

O(n) 意味着为了在给定位置插入一个对象或检索它,在最坏的情况下,您必须遍历列表中的所有 (n) 项。 因此 n 次操作。 对于 ArrayList 这只是一个操作。

你可能不能。 你不知道大小(好吧,你可以),也不知道每个元素的位置。 要在链表中查找元素 100,您需要从第 1 项开始,找到它与第 2 项的链接,依此类推,直到找到 100。这使得插入此列表成为一项乏味的工作。

根据您的确切目标,有许多替代方案。 您可以使用 b 树或类似方法将大链表拆分为较小的链表。 或者,如果您想快速查找项目,请使用哈希列表。 或者使用简单的数组。 但是如果你想要一个像 ArrayList 一样执行的列表,为什么不使用 ArrayList 呢?

您可以拆分链接到主链表的区域,这样您就可以直接在列表内提供入口点,这样您就不必走近它们。 请参阅此处的subList方法: http : //download.oracle.com/javase/1.4.2/docs/api/java/util/AbstractList.html 例如,如果您有许多由单词组成的“句子”,这将很有用。 您可以使用单独的链表来迭代句子,这些句子是主链表的子列表。

您还可以在添加、删除或访问元素时使用ListIterator 这极大地有助于提高顺序访问的速度。 请参阅listIterator方法和类: http : //download.oracle.com/javase/1.4.2/docs/api/java/util/ListIterator.html

使用跳过列表可以提高链接列表的速度: http : //igoro.com/archive/skip-lists-are-fascinating/

链表使用指针遍历项目,例如,如果您要求第 5 个项目,运行时将从第一个项目开始并遍历每个指针,直到到达第 5 个项目。

你真的无能为力。 如果您需要快速访问项目,链表可能不是一个好的选择。 尽管对其进行了一些优化,例如创建循环链表或双链表,您可以在其中来回遍历列表,但这实际上取决于业务逻辑和应用程序要求。

我的建议是避免链接列表,如果它不符合您的需求,并且更改为不同的数据结构可能是最好的方法。

作为一般规则,数据结构旨在做好某些事情。 LinkedList 被设计为在插入元素和删除元素方面比 ArrayLists 更快,并且在按顺序遍历列表时与 ArrayLists 大致相同。 当您更改 LinkedList 的工作方式时,您将使其不再是真正的 LinkedList,因此实际上没有任何方法可以将它们修改为在某些事情上更快并且仍然是 LinkedList。

您需要检查您使用这个特定集合的方式,并确定 LinkedList 是否真的是最适合您的目的的数据结构。 如果您与我们分享您如何使用它,以及您为什么需要它更快,那么我们可以建议您应该考虑使用哪种数据结构。

许多比你或我更聪明的人都看过 Java 集合类的实现。 如果要进行优化,他们会发现并已经完成。

由于集合类已尽可能优化,我们的主要任务应该是选择正确的类。

在选择集合类型时,不要忘记 HashSet 之类的东西。 如果顺序无关紧要,并且您不需要在集合中放置重复项,那么 HashSet 可能是合适的。

我是一名学生,对 Java 还很陌生。 ...如果可能的话,如何更快地制作链表?

标准的 Java 集合类型(实际上是用任何语言实现的所有数据结构!)代表对各种“措施”的妥协,例如:

  • 表示数据结构所需的内存量。
  • 执行各种操作所需的时间; 例如,对于“列表”,感兴趣的操作是插入、删除、索引、包含、迭代等。
  • 集成/重用集合类型的难易程度; 见下文。

所以例如:

  • ArrayList 提供较低的内存开销、快速索引 (O(1)),但慢速包含、随机插入和删除 (O(N))。
  • LinkedList 具有更高的内存开销、缓慢的索引和包含 (O(N)),但在某些情况下更快的删除 (O(1))。

各种性能度量通常由各种数据结构的数学决定。 例如,如果您有一个节点链,那么获得第ith节点的唯一方法是从头开始遍历它们。 这涉及遵循i指针。

有时您可以修改数据结构以提高某一方面的性能。 但这通常是以性能的其他一些方面为代价的。 (例如,您可以添加一个单独的索引以使链接列表的索引更快。但是在插入/删除时维护索引的成本意味着您可能最好使用ArrayList 。)

在某些情况下,集成/重用需求对性能有重大影响。

例如,理论上可以通过向列表元素类型添加next字段、组合元素和节点对象并为每个列表条目节省 16 字节左右来优化链表的空间使用。 但是,这会使列表类型不那么通用(成员/元素类需要实现特定的接口),并且具有元素在任何时候最多只能属于一个列表的限制。 这些限制非常有限,以至于这种方法在 Java 中很少使用。

对于第二个例子,考虑在链表中的给定位置插入的问题。 对于LinkedList类,这通常是一个O(N)操作,因为您必须遍历列表才能找到位置。 理论上,如果应用程序可以找到并记住一个位置,它应该能够在O(1)该位置执行插入。 不幸的是, List API 都没有提供“记住”位置的方法。

虽然这些示例都不是开发人员“做自己的事”的基本障碍,但它们说明使用通用数据结构 API 和这些 API 的通用实现具有性能影响,因此代表了性能和易用性之间的权衡-用。

我对这里的答案感到有些惊讶。 与 Java 实现的实际性能相比,LinkedLists 和 ArrayLists 的理论性能存在很大差异。

Java LinkedList 比理论上的 LinkedList 慢的原因在于它所做的不仅仅是操作。 例如,它检查并发修改和其他安全性。

如果你知道你的用例,你可以编写一个你自己的 LinkedList 的简单实现,它会快得多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM