Language agnostic 在什么情况下链表有用?
大多数时候,我看到人们试图使用链表,在我看来,这似乎是一个糟糕(或非常糟糕)的选择。也许有必要探讨在何种情况下链表是或不是数据结构的良好选择 理想情况下,答案将阐明选择数据结构时使用的标准,以及在特定情况下哪些数据结构可能工作得最好 编辑:我必须说,我对答案的数量和质量印象深刻。我只能接受一个,但还有两三个我不得不说,如果没有更好一点的东西,我是值得接受的。只有一对夫妇(特别是我最终接受的那一对)指出,在某些情况下,链表提供了真正的优势。我认为史蒂夫·杰索普不仅给出了一个答案,而且给出了三个不同的答案,我觉得这三个答案都给人留下了深刻的印象,因此他应该得到某种荣誉称号。当然,尽管它只是作为评论而不是答案发布,但我认为Neil的博客文章也很值得一读——不仅信息丰富,而且非常有趣。我过去在C/C++应用程序中使用过链表(甚至是双链表)。这是在.NET甚至stl之前Language agnostic 在什么情况下链表有用?,language-agnostic,data-structures,linked-list,Language Agnostic,Data Structures,Linked List,大多数时候,我看到人们试图使用链表,在我看来,这似乎是一个糟糕(或非常糟糕)的选择。也许有必要探讨在何种情况下链表是或不是数据结构的良好选择 理想情况下,答案将阐明选择数据结构时使用的标准,以及在特定情况下哪些数据结构可能工作得最好 编辑:我必须说,我对答案的数量和质量印象深刻。我只能接受一个,但还有两三个我不得不说,如果没有更好一点的东西,我是值得接受的。只有一对夫妇(特别是我最终接受的那一对)指出,在某些情况下,链表提供了真正的优势。我认为史蒂夫·杰索普不仅给出了一个答案,而且给出了三个不同
我现在可能不会在.NET语言中使用链表,因为您需要的所有遍历代码都是通过Linq扩展方法提供的。当您需要高速推送、弹出和旋转时,它们非常有用,而且不介意O(n)索引。链表非常灵活:只需修改一个指针,您可以进行大规模更改,在数组列表中,相同的操作将非常低效。它们对于并发数据结构非常有用。 (下面是一个非并发的实际使用示例——如果没有提到FORTRAN,就不会有这个示例了。) 例如,.NET4.0RC中的
ConcurrentDictionary
使用链表将散列到同一存储桶中的项目链接起来
ConcurrentStack
的底层数据结构也是一个链表
<代码>并发堆栈是作为基础的数据结构之一((本地)队列基本上是堆栈实现的。(另一个主要支撑结构是
ConcurrentQueue
)
新线程池反过来为新线程的工作调度提供了基础
因此,它们肯定是有用的——链表目前是至少一项伟大的新技术的主要支持结构之一
(在这些情况下,单链表是一个令人信服的选择,但不是等待自由的选择,因为主操作只需一次(+重试)。
在现代GC-d环境中(如Java和.NET),可以很容易地避免这种情况。
只需将您添加的项包装到新创建的节点中,而不要重用这些节点——让GC完成它的工作。
关于ABA问题的页面还提供了一个无锁堆栈的实现,该堆栈实际上在.Net(&Java)中工作,并有一个(GC-ed)节点保存这些项。)
编辑:
@尼尔:
事实上,您提到的FORTRAN提醒我,在.NET中使用和滥用最多的数据结构中也可以找到相同类型的链表:
普通.NET通用词典
不是一个,而是许多链表存储在一个数组中
- 它避免了在插入/删除时执行许多小的(取消)分配
- 哈希表的初始加载速度非常快,因为数组是按顺序填充的(CPU缓存非常好)李>
- 更不用说链式散列表在内存方面是昂贵的——而且这个“技巧”将x64上的“指针大小”减少了一半
在开始/重新刷新时分配一个数组,并在其中保留链的节点。在deletes之后还有一个自由指针(数组的索引)所以-信不信由你-FORTRAN技术仍然存在。(…在最常用的.NET数据结构之一中;-)。当您需要对任意(编译时未知)长度的列表进行大量插入和删除,但不需要太多搜索时,链表非常有用 拆分和连接(双向链接)列表非常有效 您还可以组合链表-例如,树结构可以实现为“垂直”链表(父/子关系),将水平链表(同级)连接在一起 出于这些目的使用基于阵列的列表有严重的局限性:
- 添加新项意味着必须重新分配阵列(或者必须分配比需要更多的空间,以允许未来的增长并减少重新分配的数量)
- 删除项目会浪费空间或需要重新分配
- 在除末端以外的任何位置插入项都涉及(可能重新分配和)将大量数据复制到一个位置
双链表是定义hashmap顺序的好选择,hashmap还定义元素的顺序(Java中的LinkedHashMap),尤其是按上次访问排序时:
struct FaceVertex
{
// Points to next vertex in polygon or -1
// if we're at the end of the polygon.
int next;
...
};
struct Polygon
{
// Points to first vertex in polygon.
int first_vertex;
...
};
struct Mesh
{
// Stores all the face vertices for all polygons.
std::vector<FaceVertex> fvs;
// Stores all the polygons.
std::vector<Polygon> polys;
};