简体   繁体   English

加速链表?

[英]Speeding up a linked list?

I'm a student and fairly new to Java.我是一名学生,对 Java 还很陌生。 I was looking over the different speeds achieved by the two collections in Java, Linked List, and ArrayList.我查看了 Java、Linked List 和 ArrayList 中的两个集合实现的不同速度。 I know that an ArrayList is much much faster at looking up and placing in values into its indexes.我知道 ArrayList 在查找和将值放入其索引时要快得多。 My question is:我的问题是:

how can one make a linked list faster, if at all possible?如果可能的话,如何使链表更快?

Thanks for any help.谢谢你的帮助。

zmahir兹马希尔

When talking about speed, perhaps you mean complexity .在谈论速度时,您可能指的是复杂性 Insertion and retrieval operations for ArrayList (and arrays) are O(1), while for LinkedList they are O(n). ArrayList (和数组)的插入和检索操作是 O(1),而对于LinkedList它们是 O(n)。 And this cannot be changed - it is 'by definition'.这不能改变——它是“根据定义”的。

O(n) means that in order to insert an object at a given position, or retrieve it, you must traverse, in the worst case, all (n) the items in the list. O(n) 意味着为了在给定位置插入一个对象或检索它,在最坏的情况下,您必须遍历列表中的所有 (n) 项。 Hence n operations.因此 n 次操作。 For ArrayList this is only one operation.对于 ArrayList 这只是一个操作。

You probably can't.你可能不能。 You don't know the size (well, ok you can), nor the location of each element.你不知道大小(好吧,你可以),也不知道每个元素的位置。 To find element 100 in a linked list, you need to start with item 1, find it's link to item 2, etc. until you find 100. This makes inserting into this list a tedious job.要在链表中查找元素 100,您需要从第 1 项开始,找到它与第 2 项的链接,依此类推,直到找到 100。这使得插入此列表成为一项乏味的工作。

There are many alternatives depending on your exact goals.根据您的确切目标,有许多替代方案。 You can use b-trees or similar methods to split the large linked list into smaller ones.您可以使用 b 树或类似方法将大链表拆分为较小的链表。 Or use hashlists if you want to quickly find items.或者,如果您想快速查找项目,请使用哈希列表。 Or use simple arrays.或者使用简单的数组。 But if you want a list that performs like an ArrayList, why not use an ArrayList?但是如果你想要一个像 ArrayList 一样执行的列表,为什么不使用 ArrayList 呢?

You can split off regions which are linked to the main linked list, so this gives you entry points directly inside the list so you don't have to walk up to them.您可以拆分链接到主链表的区域,这样您就可以直接在列表内提供入口点,这样您就不必走近它们。 See the subList method here: http://download.oracle.com/javase/1.4.2/docs/api/java/util/AbstractList.html .请参阅此处的subList方法: http : //download.oracle.com/javase/1.4.2/docs/api/java/util/AbstractList.html This is useful if you have a number of 'sentences' made out of words, say.例如,如果您有许多由单词组成的“句子”,这将很有用。 You can use a separate linked list to iterate over the sentences, which are sublists of the main linked list.您可以使用单独的链表来迭代句子,这些句子是主链表的子列表。

You can also use a ListIterator when adding, removing, or accessing elements.您还可以在添加、删除或访问元素时使用ListIterator This helps greatly with increasing the speed of sequential access.这极大地有助于提高顺序访问的速度。 See the listIterator method for this, and the class: http://download.oracle.com/javase/1.4.2/docs/api/java/util/ListIterator.html .请参阅listIterator方法和类: http : //download.oracle.com/javase/1.4.2/docs/api/java/util/ListIterator.html

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

a linked list uses pointers to walk through the items, so for example if you asked for the 5th item, the runtime will start from the first item and walks through each pointer until it reaches the 5th item.链表使用指针遍历项目,例如,如果您要求第 5 个项目,运行时将从第一个项目开始并遍历每个指针,直到到达第 5 个项目。

there is really not much you can do about it.你真的无能为力。 a linked list may not be a good choice if you need fast acces to items.如果您需要快速访问项目,链表可能不是一个好的选择。 although there are some optimizations for it such as creating a circular linked list or a double linked list where you can walk back and forth the list but this really depends on the business logic and the application requirements.尽管对其进行了一些优化,例如创建循环链表或双链表,您可以在其中来回遍历列表,但这实际上取决于业务逻辑和应用程序要求。

my advise is to avoid linked lists if it does not match your needs and changing to a different data structure might be the best approach.我的建议是避免链接列表,如果它不符合您的需求,并且更改为不同的数据结构可能是最好的方法。

As a general rule, data structures are designed to do certain things well.作为一般规则,数据结构旨在做好某些事情。 LinkedLists are designed to be faster than ArrayLists at inserting elements and removing elements and about the same as ArrayLists at iterating across the list in order. LinkedList 被设计为在插入元素和删除元素方面比 ArrayLists 更快,并且在按顺序遍历列表时与 ArrayLists 大致相同。 When you change the way a LinkedList works, you make it no longer a true LinkedList, so there's not really any way to modify them to be faster at something and still be a LinkedList.当您更改 LinkedList 的工作方式时,您将使其不再是真正的 LinkedList,因此实际上没有任何方法可以将它们修改为在某些事情上更快并且仍然是 LinkedList。

You'll need to examine the way you're using this particular collection and decide whether a LinkedList is really the best data structure for your purposes.您需要检查您使用这个特定集合的方式,并确定 LinkedList 是否真的是最适合您的目的的数据结构。 If you share with us how you're using it, and why you need it to be faster, then we can advise you on which data structure you ought to consider using.如果您与我们分享您如何使用它,以及您为什么需要它更快,那么我们可以建议您应该考虑使用哪种数据结构。

Lots of people smarter than you or I have looked at the implementation of the Java collection classes.许多比你或我更聪明的人都看过 Java 集合类的实现。 If there were an optimization to be made, they would have found it and already made it.如果要进行优化,他们会发现并已经完成。

Since the collection classes are pretty much as optimized as they can be, our primary task should be to choose the correct one.由于集合类已尽可能优化,我们的主要任务应该是选择正确的类。

When choosing your collection type, don't forget about things like HashSet.在选择集合类型时,不要忘记 HashSet 之类的东西。 If order doesn't matter, and you don't need to put duplicates in the collection, then HashSet may be appropriate.如果顺序无关紧要,并且您不需要在集合中放置重复项,那么 HashSet 可能是合适的。

I'm a student and fairly new to Java.我是一名学生,对 Java 还很陌生。 ... how can one make a linked list faster, if at all possible? ...如果可能的话,如何更快地制作链表?

The standard Java collection type (indeed all data structures implemented in any language!) represent compromises on various "measures" such as:标准的 Java 集合类型(实际上是用任何语言实现的所有数据结构!)代表对各种“措施”的妥协,例如:

  • The amount of memory needed to represent the data structure.表示数据结构所需的内存量。
  • The time taken to perform various operations;执行各种操作所需的时间; eg for a "list" the operations of interest are insertion, removal, indexing, contains, iteration and so on.例如,对于“列表”,感兴趣的操作是插入、删除、索引、包含、迭代等。
  • How easy or hard it is to integrate / reuse the collection type;集成/重用集合类型的难易程度; see below.见下文。

So for instance:所以例如:

  • ArrayList offers lower memory overheads, fast indexing (O(1)), but slow contains, random insertion and removal (O(N)). ArrayList 提供较低的内存开销、快速索引 (O(1)),但慢速包含、随机插入和删除 (O(N))。
  • LinkedList has higher memory overheads, slow indexing and contains (O(N)), but faster removal (O(1)) under certain circumstances . LinkedList 具有更高的内存开销、缓慢的索引和包含 (O(N)),但在某些情况下更快的删除 (O(1))。

The various performance measures are typically determines by the maths of the various data structures.各种性能度量通常由各种数据结构的数学决定。 For example, if you have a chain of nodes, the only way to get the ith node is to step through them from the beginning.例如,如果您有一个节点链,那么获得第ith节点的唯一方法是从头开始遍历它们。 This involves following i pointers.这涉及遵循i指针。

Sometimes you can modify the data structures to improve one aspect of the performance.有时您可以修改数据结构以提高某一方面的性能。 But this typically comes at the cost of some other aspect of the performance.但这通常是以性能的其他一些方面为代价的。 (For example, you could add a separate index to make indexing of a linked list faster. But the cost of maintaining the index on insertion / deletion would mean that you'd probably be better of using an ArrayList .) (例如,您可以添加一个单独的索引以使链接列表的索引更快。但是在插入/删除时维护索引的成本意味着您可能最好使用ArrayList 。)

In some cases the integration / reuse requirements have significant impact on performance.在某些情况下,集成/重用需求对性能有重大影响。

For example, it is theoretically possible to optimize a linked list's space usage by adding a next field to the list element type, combining the element and node objects and saving 16 or so bytes per list entry.例如,理论上可以通过向列表元素类型添加next字段、组合元素和节点对象并为每个列表条目节省 16 字节左右来优化链表的空间使用。 However, this would make the list type less general (the member/element class would need to implement a specific interface), and has the restriction that an element can belong to at most one list at any time.但是,这会使列表类型不那么通用(成员/元素类需要实现特定的接口),并且具有元素在任何时候最多只能属于一个列表的限制。 These restrictions are so limiting that this approach is rarely used in Java.这些限制非常有限,以至于这种方法在 Java 中很少使用。

For a second example, consider the problem of inserting at a given position in a linked list.对于第二个例子,考虑在链表中的给定位置插入的问题。 For the LinkedList class, this is normally an O(N) operation, because you have to step through the list to find the position.对于LinkedList类,这通常是一个O(N)操作,因为您必须遍历列表才能找到位置。 In theory, if an application could find and remember a position, it should be able to perform the insertion at that position in O(1) .理论上,如果应用程序可以找到并记住一个位置,它应该能够在O(1)该位置执行插入。 Unfortunately, neither the List APIs provides no way to "remember" a position.不幸的是, List API 都没有提供“记住”位置的方法。

While neither of these examples is a fundamental roadblock to a developer "doing his own thing", they illustrate that using general data structure APIs and general implementations of those APIs has performance implications, and therefore represents a trade-off between performance and ease-of-use.虽然这些示例都不是开发人员“做自己的事”的基本障碍,但它们说明使用通用数据结构 API 和这些 API 的通用实现具有性能影响,因此代表了性能和易用性之间的权衡-用。

I'm a bit surprised by the answers here.我对这里的答案感到有些惊讶。 There are big difference between the theoretical performance of LinkedLists and ArrayLists compared to the actual performance of the Java implementations.与 Java 实现的实际性能相比,LinkedLists 和 ArrayLists 的理论性能存在很大差异。

What makes the Java LinkedList slower than a theoretical LinkedList is that it does a lot more than just the operations. Java LinkedList 比理论上的 LinkedList 慢的原因在于它所做的不仅仅是操作。 For example it checks for concurrent modifications and other safeties.例如,它检查并发修改和其他安全性。

If you know your use case, you can write a your own simple implementation of a LinkedList and it will be much faster.如果你知道你的用例,你可以编写一个你自己的 LinkedList 的简单实现,它会快得多。

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

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