简体   繁体   English

什么是应该使用链接列表的真实世界示例?

[英]What are real world examples of when Linked Lists should be used?

Another programmer was mentioning that they haven't found a use case for using a linked list data structure in any professional software in his career.另一位程序员提到,在他的职业生涯中,他们还没有找到在任何专业软件中使用链表数据结构的用例。 I couldn't think of any good examples off the top of my head.我想不出任何好的例子。 He is mostly a C# and Java developer他主要是 C# 和 Java 开发人员

Can anyone give some examples where this was the correct data structure to solve a particular real world problem?任何人都可以举一些例子,说明这是解决特定现实世界问题的正确数据结构吗?

Related: What is a practical, real world example of the Linked List?相关:链接列表的实际示例是什么?

Linked Lists offer several advantages over comparable data structures such as static or dynamically expanding arrays.与类似的数据结构(例如 static 或动态扩展 arrays)相比,链表提供了几个优势。

  1. LinkedLists does not require contiguous blocks of memory and therefore can help reduce memory fragmentation LinkedLists 不需要 memory 的连续块,因此可以帮助减少 memory 碎片
  2. LinkedLists support efficient removal of elements (dynamic arrays usually force a shift in all of the elements). LinkedLists 支持有效删除元素(动态 arrays 通常会强制所有元素移动)。
  3. LinkedLists support efficient addition of elements (dynamic arrays can cause a re-allocation + copy, if a particular add exceeds the current capacity) LinkedLists 支持元素的高效添加(如果特定添加超出当前容量,动态 arrays 会导致重新分配 + 复制)

Any place where these advantages would be significantly valuable to a program (and the disadvantages of a LinkedList were negligible) would be a place to use a LinkedList.任何这些优点对程序非常有价值的地方(并且 LinkedList 的缺点可以忽略不计)都将是使用 LinkedList 的地方。

A real-world example would be a FIFO queue.一个真实的例子是 FIFO 队列。 An simple array-based list is pretty bad for that because you need to add at one end and remove at the other end, and one of those operations will be O(n) with an array-based list (unless you add extra logic to work with a start AND end index), while both are O(1) with a linked list without extra effort.一个简单的基于数组的列表对此非常不利,因为您需要在一端添加并在另一端删除,其中一个操作将是 O(n) 与基于数组的列表(除非您添加额外的逻辑使用开始和结束索引),而两者都是 O(1) 使用链表而不需要额外的努力。

Intrusive linked lists are interesting beasts for game development.侵入式链表是游戏开发的有趣野兽。 For example, it's somewhat common practice to have an intrusive singly- or doubly-linked "render" list:例如,有一个侵入性的单链接或双链接“渲染”列表是一种常见的做法:

class Renderable /* or class Object, whatever */
{
  // ...
  Renderable * m_pNext;
  Renderable * m_pPrev; // or not, if singly-linked
  // ...
}

As Renderables come into and out of existence they can register themselves with this list -- without causing any memory allocation.随着可渲染对象的出现和消失,它们可以在此列表中注册自己——而不会导致任何 memory 分配。 If their render depth or priority is changed they can remove and reinsert themselves, etc.如果他们的渲染深度或优先级被改变,他们可以移除并重新插入自己,等等。

When it comes time to render, all you need to do is find the head of the list and zip through, calling the appropriate method!到了渲染的时候,你需要做的就是找到列表的头部和zip,调用相应的方法!

(There are, of course, many variations on this theme, with multiple separate lists, etc. And you don't need to have an intrusive list to make this work, I just find the intrusive ones interesting.) (当然,这个主题有很多变体,有多个单独的列表等。而且你不需要有一个侵入性的列表来完成这项工作,我只是觉得侵入性的列表很有趣。)

Linked Lists ( paired with a hashtable ) are really useful for LRU Caches .链表( 与散列表配对)对于LRU 缓存非常有用。

Every Get needs to bump a node to the front of the list, an operation that is really cheap with linked lists.每个 Get 都需要将一个节点撞到列表的前面,这个操作对于链表来说真的很便宜。

Stacks and queues are very clear examples of linked lists, but as other already have mentioned them I'd like to add a few other examples:堆栈和队列是链表的非常清楚的例子,但正如其他人已经提到的那样,我想添加一些其他例子:

DOM stores nodes as linked lists. DOM 将节点存储为链表。 A simple javascript sample that is really the same in any language:一个简单的 javascript 示例,在任何语言中都完全相同:

for (var node = parent.firstChild; node != null; node = node.nextSibling) {
    // ..
}

I would imagine that a java developer has come across XML at some point.我想 java 开发人员在某个时候遇到了 XML。

Trees are another good examples of linked lists, even though they aren't simple one dimensional ones.树是链表的另一个很好的例子,尽管它们不是简单的一维的。 Someone who's done a lot of java development has probably come across TreeMaps and TreeSets.做过很多 java 开发的人可能遇到过 TreeMaps 和 TreeSets。

The entire discussion seems a bit silly to me.整个讨论对我来说似乎有点愚蠢。 Linked lists are a fundamental data structure that is used everywhere.链表是一种无处不在的基本数据结构。 The only reason that one might think that he/she hasn't come across them is that you don't really have to worry about the implementation of data structures in todays high level languages, but of course they're still there.人们可能认为他/她没有遇到过它们的唯一原因是您实际上不必担心当今高级语言中数据结构的实现,但它们当然仍然存在。

Some example of single linked list.单链表的一些例子。

  1. Undo button of any application like Microsoft Word, Paint, etc: A linked list of states. Microsoft Word、Paint 等任何应用程序的撤消按钮:状态链接列表。
  2. GPS Navigation: A linked list of map data. GPS 导航:map 数据的链表。 Travelling from origin to destination is example of traversing through all nodes.从起点到终点的旅行是遍历所有节点的示例。 Rerouting by a GPS is an example of Add and Remove operations of map data.通过 GPS 重新路由是 map 数据的添加和删除操作的示例。

Some example of double linked list.双链表的一些例子。

  1. Browser's Next and Previous Button: a linked list of URLs.浏览器的下一个和上一个按钮:一个链接的 URL 列表。
  2. Image Viewer's Next and Previous Button: a linked list of images图像查看器的下一个和上一个按钮:图像的链接列表
  3. Undo and Redo button of Photoshop, a linked list of states. Photoshop 的撤消和重做按钮,状态链接列表。

They occur all the time, anywhere an object has a property that points to another object of the same type.它们一直在发生,只要 object 具有指向同一类型的另一个 object 的属性。 In the CLR, exceptions form a linked list, due to the InnerException property.在 CLR 中,由于InnerException属性,异常形成了一个链表。

An immutable linked list is a very valuable structure, since you can 'share structure' with other lists with the same tail.不可变链表是一种非常有价值的结构,因为您可以与其他具有相同尾部的列表“共享结构”。 Most functional languages include an immutable linked list type as one of their fundamental data structures, and these types are used all over the place.大多数函数式语言都包含一个不可变的链表类型作为它们的基本数据结构之一,并且这些类型在所有地方都被使用。

I wrote a BIOS extension (basically a device driver for a BIOS, written in assembly) for a USB host controller.我为 USB 主机 controller 编写了 BIOS 扩展(基本上是 BIOS 的设备驱动程序,用汇编语言编写)。 -- Implementing a high-level seemingly abstract data structure like a linked list in assembly isn't as hard as it sounds. -- 在汇编中实现像链表这样的高级看似抽象的数据结构并不像听起来那么难。 -- The controller serviced I/O requests for keyboard and disk using a linked list of packets in main memory. -- controller 使用主 memory 中的数据包链接列表为键盘和磁盘的 I/O 请求提供服务。 I maintained a pool of free packets in another linked list.我在另一个链表中维护了一个免费数据包池。 Performing I/O basically involved grabbing a free packet from the beginning of the free list, configuring the packet, adding the packet to the device's list, and re-adding the packet to the beginning of the free pool when the I/O finished.执行 I/O 基本上包括从空闲列表的开头抓取一个空闲数据包,配置数据包,将数据包添加到设备列表中,并在 I/O 完成时将数据包重新添加到空闲池的开头。 Linked lists are lightning fast for moving around objects like this, especially when the objects are large, since the objects don't actually have to move.链表对于像这样在对象周围移动非常快,尤其是当对象很大时,因为对象实际上不必移动。 Only their pointers need to be updated.只有它们的指针需要更新。

An array-based queue would have required:基于数组的队列需要:

  • using a begin/end index pointer, which is fast but requires fixing the size of the queue so that the producer has to wait when the consumer's queue is full and locking the queue while the whole packet is filled if there is more than one producer使用开始/结束索引指针,这很快但需要固定队列的大小,以便生产者必须在消费者队列已满时等待,如果有多个生产者,则在整个数据包填满时锁定队列
  • shifting all the elements in the queue whenever you insert/remove, which is slow for large objects每当您插入/删除时移动队列中的所有元素,这对于大型对象来说很慢

So, linked lists are a nice way to implement an arbitrarily long first-in-first-out queue of large objects.因此,链表是实现任意长的大对象先进先出队列的好方法。

Another thing to be careful about is that for small objects or where you allocate objects from a conventional heap instead of a custom free pool, arrays can be faster because copying isn't really that slow if it's not done that often, and the repeated allocation from the heap that a linked list would require every time a new element is added is slow.另一件需要注意的事情是,对于小对象或从常规堆而不是自定义空闲池分配对象的地方,arrays 可以更快,因为如果不经常进行复制并不会那么慢,并且重复分配每次添加新元素时,链表都需要从堆中获取速度很慢。

Of course, you may want to simulate and measure your particular scenario with some throwaway test code to find the answer.当然,您可能希望使用一些一次性测试代码来模拟和测量您的特定场景以找到答案。 I like to run loops a few million times with linked lists and arrays, with small and large objects, and time how long each takes in real time.我喜欢用链表和 arrays 运行几百万次循环,用小对象和大对象,以及每个实时需要多长时间。 Sometimes you'll be surprised.有时你会感到惊讶。

As perhaps the best real world example in.Net consider the MultiCastDelegate .作为.Net 中最好的现实世界示例,请考虑MultiCastDelegate

Linked lists implemented in this way, where the list chaining aspect is backed directly into the type rather than as a separate container, can be extremely powerful and efficient.以这种方式实现的链接列表,其中列表链接方面直接支持到类型中而不是作为单独的容器,可以非常强大和高效。 They come however with a variety of trade offs.然而,它们伴随着各种权衡。
One obvious one is code duplication, you must bake this logic in each type.一个明显的问题是代码重复,您必须在每种类型中烘焙此逻辑。 Techniques such as extending a base class providing the pointer are messy (you lose strong typing without generics) and often unacceptable from a performance point of view.诸如扩展基础 class 提供指针的技术是混乱的(如果没有泛型,您会失去强类型)并且从性能的角度来看通常是不可接受的。
Another is that you are limited to one implementation per type.另一个是您仅限于每种类型的一个实现。 You cannot make a singly linked structure into a doubly linked one without inserting an extra field in every instance and updating all the relevant code.如果不在每个实例中插入一个额外的字段并更新所有相关代码,就无法将单链接结构变成双链接结构。

Linked list is the essential data structure for Dancing Links , which is the technique used to efficiently implement Algorithm X , which is a backtracking algorithm to find all solutions to the NP-complete exact cover problem, to which many hard problems are naturally reducible to.链表是Dancing Links的基本数据结构,它是用于有效实现算法 X的技术,它是一种回溯算法,用于找到 NP 完全精确覆盖问题的所有解决方案,许多难题自然可以简化为。

As said already linked lists are very useful when you need to insert and delete elements.如前所述,当您需要插入和删除元素时,链表非常有用。

For example to help debug memory management in my code I recently implemeneted a link list between all my refrence counted objects so that at the end of the program (when the refrences should all have hit zero and deleted the objects) I could see exactly what was still left, useually resulting in me being able to find a single object at the root of the problem.例如,为了帮助在我的代码中调试 memory 管理,我最近在我的所有参考计数对象之间实现了一个链接列表,以便在程序结束时(当参考应该全部达到零并删除对象时)我可以确切地看到是什么仍然存在,通常导致我能够在问题的根源上找到单个 object。

CPython implements something similir with a massive linked list between nearly every when its built with debugging. CPython 实现了类似的东西,它几乎在每一个构建时都带有一个庞大的链表,并带有调试功能。

Answering to the tag 'Data Structures', at a low level such as assembly, linked lists are an ideal way to store variable length lists of other data structures.响应标签“数据结构”,在汇编等低级别,链表是存储其他数据结构的可变长度列表的理想方式。 There is no overhead for maintaining the list length or end, and there no is need for fixed size list items.维护列表长度或结尾没有开销,也不需要固定大小的列表项。 The last reason also applies to higher level languages.最后一个原因也适用于高级语言。

If I may answer this question in a slightly different manner than others have, lately I've been using linked lists to organize music lists.如果我可以以与其他人略有不同的方式回答这个问题,那么最近我一直在使用链接列表来组织音乐列表。 The lists provide an excellent way to store and sort through music by artist, song, album, even ratings or song length.这些列表提供了一种按艺术家、歌曲、专辑甚至收视率或歌曲长度存储和排序音乐的绝佳方式。 Mine is a doubly linked list, but I could see it being applicable with a singly linked list as well.我的是一个双向链表,但我可以看到它也适用于单链表。 Shopping lists would fit as well, and if you're OCD like my mom, you can easily organize it be aisle and frozen foods last!购物清单也很合适,如果你像我妈妈一样有强迫症,你可以很容易地把它整理成过道和最后的冷冻食品!

If we include stacks and queues, the obvious for queues is a print queue or a music playlist (lists in any sense are good obviously).如果我们包括堆栈和队列,那么队列显然是打印队列或音乐播放列表(显然任何意义上的列表都很好)。

As daustin777 points out, linked lists are all around you and you may not even know it.正如 daustin777 指出的那样,链表就在你身边,你甚至可能都不知道。 But the practicality of the matter is that they allow for some pretty basic operations to be performed with relative ease and flexibility.但问题的实用性在于它们允许以相对容易和灵活的方式执行一些非常基本的操作。 For example, not to sort, just swap pointers around.例如,不排序,只是交换指针。 Need to insert or remove at arbitrary places?需要在任意位置插入或移除? Insert or remove your pointers within the list.在列表中插入或删除您的指针。 Need to iterate forwards and backwards... linked list.需要向前和向后迭代...链表。 While not precisely a business example, I hope this clarifies it enough for you to apply it to your own real world business case.虽然不完全是一个商业示例,但我希望这足以澄清它,以便您将其应用到您自己的真实世界商业案例中。

Stacks and Queues are examples of linked lists.堆栈和队列是链表的示例。

For problems where the number of maximal nodes are constrained to 100 or below or so, linked lists are a reasonable solution.对于最大节点数限制在 100 或以下的问题,链表是一个合理的解决方案。 The same can be true of things like bubble sort and other things that are thought to be sub-optimal.冒泡排序和其他被认为是次优的事情也是如此。

Linked list implementation spotted in the wild:在野外发现的链表实现:

Python's LRU cache : Python 的 LRU 缓存

...
...
    cache_get = cache.get    # bound method to lookup a key or return None
    cache_len = cache.__len__  # get cache size without calling len()
    lock = RLock()           # because linkedlist updates aren't threadsafe
    root = []                # root of the circular doubly linked list
...
...

Yet notice that the _lru_cache_wrapper function is actually imported from the C module implementation :但请注意, _lru_cache_wrapper function 实际上是从C module 实现导入的:

...
...
typedef struct lru_list_elem {
    PyObject_HEAD
    struct lru_list_elem *prev, *next;  /* borrowed links */
    Py_hash_t hash;
    PyObject *key, *result;
} lru_list_elem;
...
...

Linked list pros:链表优点:

  • Dynamic storage nullifies fragmentation动态存储消除碎片
  • Fast insertion / removal快速插入/移除
  • Fast access to first element (and end if implemented bidirectional)快速访问第一个元素(如果双向实现则结束)
  • Efficient memory usage高效的 memory 使用

Linked list cons:链表缺点:

  • Slow traversing慢速穿越

Out of my head, I'd implement stacks, queues and messagepumps using linked lists.在我的脑海中,我会使用链表来实现堆栈、队列和消息泵。 I'd also implement a datatree using multi-reference linked-lists for fast insertion / removal.我还将使用多引用链接列表实现数据树,以实现快速插入/删除。

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

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