我应该什么时候使用List和LinkedList ?

时间:2022-09-10 22:54:14

When is it better to use a List(Of T) vs a LinkedList(Of T)?

什么时候使用List(T)和LinkedList(T)比较好?

15 个解决方案

#1


101  

Edit

Please read the comments to this answer. People claim I did not do proper tests. I agree this should not be an accepted answer. As I was learning I did some tests and felt like sharing them.

请阅读下面的评论。人们声称我没有做适当的测试。我同意这不是一个公认的答案。在我学习的过程中,我做了一些测试,想要分享它们。

Original answer...

I found interesting results:

我发现了有趣的结果:

// Temporary class to show the example
class Temp
{
    public decimal A, B, C, D;

    public Temp(decimal a, decimal b, decimal c, decimal d)
    {
        A = a;            B = b;            C = c;            D = d;
    }
}

Linked list (3.9 seconds)

        LinkedList<Temp> list = new LinkedList<Temp>();

        for (var i = 0; i < 12345678; i++)
        {
            var a = new Temp(i, i, i, i);
            list.AddLast(a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

List (2.4 seconds)

        List<Temp> list = new List<Temp>(); // 2.4 seconds

        for (var i = 0; i < 12345678; i++)
        {
            var a = new Temp(i, i, i, i);
            list.Add(a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

Even if you only access data essentially it is much slower!! I say never use a linkedList.

即使你只访问数据,实际上它要慢得多!!我说永远不要使用linkedList。




Here is another comparison performing a lot of inserts (we plan on inserting an item at the middle of the list)

这里是另一个执行大量插入的比较(我们计划在列表的中间插入一个项目)

Linked List (51 seconds)

        LinkedList<Temp> list = new LinkedList<Temp>();

        for (var i = 0; i < 123456; i++)
        {
            var a = new Temp(i, i, i, i);

            list.AddLast(a);
            var curNode = list.First;

            for (var k = 0; k < i/2; k++) // In order to insert a node at the middle of the list we need to find it
                curNode = curNode.Next;

            list.AddAfter(curNode, a); // Insert it after
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

List (7.26 seconds)

        List<Temp> list = new List<Temp>();

        for (var i = 0; i < 123456; i++)
        {
            var a = new Temp(i, i, i, i);

            list.Insert(i / 2, a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

Linked List having reference of location where to insert (.04 seconds)

        list.AddLast(new Temp(1,1,1,1));
        var referenceNode = list.First;

        for (var i = 0; i < 123456; i++)
        {
            var a = new Temp(i, i, i, i);

            list.AddLast(a);
            list.AddBefore(referenceNode, a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

So only if you plan on inserting several items and you also somewhere have the reference of where you plan to insert the item then use a linked list. Just because you have to insert a lot of items it does not make it faster because searching the location where you will like to insert it takes time.

因此,只有当您计划插入多个项目时,您还可以在某个地方引用您计划插入该项目的位置,然后使用一个链表。仅仅因为你需要插入很多项,它不会使它更快,因为搜索你想插入的位置需要时间。

#2


230  

In most cases, List<T> is more useful. LinkedList<T> will have less cost when adding/removing items in the middle of the list, whereas List<T> can only cheaply add/remove at the end of the list.

在大多数情况下,List 更有用。当在列表中间添加/移除项时,LinkedList< t>的成本会更低,而list 只能在列表的末尾添加/删除。

LinkedList<T> is only at it's most efficient if you are accessing sequential data (either forwards or backwards) - random access is relatively expensive since it must walk the chain each time (hence why it doesn't have an indexer). However, because a List<T> is essentially just an array (with a wrapper) random access is fine.

LinkedList 只是在访问顺序数据(向前或向后)时效率最高,因为每次随机存取都比较昂贵,因为它每次都必须遍历链(因此它没有索引器)。但是,因为List 实际上只是一个数组(带有一个包装器),所以随机访问很好。

List<T> also offers a lot of support methods - Find, ToArray, etc; however, these are also available for LinkedList<T> with .NET 3.5/C# 3.0 via extension methods - so that is less of a factor.

List 还提供了许多支持方法——Find、ToArray等;但是,这些也可以通过扩展方法使用。net 3.5/ c# 3.0,这是一个更少的因素。

#3


182  

Thinking of a linked list as a list can be a bit misleading. It's more like a chain. In fact, in .NET, LinkedList<T> does not even implement IList<T>. There is no real concept of index in a linked list, even though it may seem there is. Certainly none of the methods provided on the class accept indexes.

把一个链表看作一个列表可能有点误导。它更像一条链。事实上,在。net中,LinkedList 甚至没有实现IList 。在一个链表中没有真正的索引概念,即使它看起来有。当然,类中提供的方法都不接受索引。

Linked lists may be singly linked, or doubly linked. This refers to whether each element in the chain has a link only to the next one (singly linked) or to both the prior/next elements (doubly linked). LinkedList<T> is doubly linked.

链接列表可能是单链接的,或者是双向链接的。这是指链中的每个元素是否只链接到下一个(单个链接)或之前/下一个元素(双链接)。LinkedList < T >是双向链。

Internally, List<T> is backed by an array. This provides a very compact representation in memory. Conversely, LinkedList<T> involves additional memory to store the bidirectional links between successive elements. So the memory footprint of a LinkedList<T> will generally be larger than for List<T> (with the caveat that List<T> can have unused internal array elements to improve performance during append operations.)

在内部,List 由一个数组支持。这在内存中提供了一个非常紧凑的表示。相反,LinkedList 包含了额外的内存来存储连续元素之间的双向链接。因此,LinkedList< t>的内存占用通常比List 更大(需要注意的是,List 可以有未使用的内部数组元素来提高append操作期间的性能)。

They have different performance characteristics too:

它们的性能也不同:

Append

  • LinkedList<T>.AddLast(item) constant time
  • LinkedList < T > .AddLast常数时间(项)
  • List<T>.Add(item) amortized constant time, linear worst case
  • 列表 .Add(项)平摊常数时间,线性最坏情况。

Prepend

  • LinkedList<T>.AddFirst(item) constant time
  • LinkedList < T > .AddFirst常数时间(项)
  • List<T>.Insert(0, item) linear time
  • < T >列表。插入(0,项)线性时间

Insertion

  • LinkedList<T>.AddBefore(node, item) constant time
  • LinkedList < T >。AddBefore节点,项目持续时间
  • LinkedList<T>.AddAfter(node, item) constant time
  • LinkedList < T >。AddAfter节点,项目持续时间
  • List<T>.Insert(index, item) linear time
  • < T >列表。插入(指数项)线性时间

Removal

  • LinkedList<T>.Remove(item) linear time
  • LinkedList < T > .Remove(项)线性时间
  • LinkedList<T>.Remove(node) constant time
  • LinkedList < T > .Remove(节点)持续的时间
  • List<T>.Remove(item) linear time
  • < T > .Remove列表(项)线性时间
  • List<T>.RemoveAt(index) linear time
  • < T > .RemoveAt列表(指数)线性时间

Count

  • LinkedList<T>.Count constant time
  • LinkedList < T >。计算常数时间
  • List<T>.Count constant time
  • < T >列表。计算常数时间

Contains

  • LinkedList<T>.Contains(item) linear time
  • LinkedList < T > .Contains(项)线性时间
  • List<T>.Contains(item) linear time
  • < T > .Contains列表(项)线性时间

Clear

  • LinkedList<T>.Clear() linear time
  • LinkedList < T > .Clear()线性时间
  • List<T>.Clear() linear time
  • < T > .Clear列表()线性时间

As you can see, they're mostly equivalent. In practice, the API of LinkedList<T> is more cumbersome to use, and details of its internal needs spill out into your code.

正如你所看到的,它们基本上是等价的。在实践中,LinkedList 的API使用起来更麻烦,其内部需求的细节会溢出到您的代码中。

However, if you need to do many insertions/removals from within a list, it offers constant time. List<T> offers linear time, as extra items in the list must be shuffled around after the insertion/removal.

但是,如果您需要从列表中执行许多插入/删除操作,它提供了常量时间。列表 提供了线性时间,因为在插入/删除之后,列表中的额外项必须被拖拽。

#4


112  

Linked lists provide very fast insertion or deletion of a list member. Each member in a linked list contains a pointer to the next member in the list so to insert a member at position i:

链表提供非常快的插入或删除列表成员。链表中的每个成员都包含一个指向列表中的下一个成员的指针,以便在position i中插入一个成员:

  • update the pointer in member i-1 to point to the new member
  • 更新成员i-1中的指针指向新成员。
  • set the pointer in the new member to point to member i
  • 设置新成员中的指针指向成员i。

The disadvantage to a linked list is that random access is not possible. Accessing a member requires traversing the list until the desired member is found.

链表的缺点是不可能随机访问。访问成员需要遍历列表,直到找到所需的成员。

#5


16  

The difference between List and LinkedList lies in their underlying implementation. List is array based collection (ArrayList). LinkedList is node-pointer based collection (LinkedListNode). On the API level usage, both of them are pretty much the same since both implement same set of interfaces such as ICollection, IEnumerable, etc.

List和LinkedList的区别在于它们的底层实现。List是基于数组的集合(ArrayList)。LinkedList是基于节点指针的集合(LinkedListNode)。在API级别的使用上,它们几乎是相同的,因为它们都实现了相同的接口集,比如ICollection、IEnumerable等。

The key difference comes when performance matter. For example, if you are implementing the list that has heavy "INSERT" operation, LinkedList outperforms List. Since LinkedList can do it in O(1) time, but List may need to expand the size of underlying array. For more information/detail you might want to read up on the algorithmic difference between LinkedList and array data structures. http://en.wikipedia.org/wiki/Linked_list and Array

关键的区别在于性能问题。例如,如果您正在实现具有重“插入”操作的列表,LinkedList将超过列表。因为LinkedList可以在O(1)时间内完成,但是列表可能需要扩展底层数组的大小。要了解更多信息/细节,您可能需要了解LinkedList和数组数据结构之间的算法差异。http://en.wikipedia.org/wiki/Linked_list和数组

Hope this help,

希望这个有帮助,

#6


10  

The primary advantage of linked lists over arrays is that the links provide us with the capability to rearrange the items efficiently. Sedgewick, p. 91

链表与数组的主要优点是,这些链接为我们提供了有效地重新排列项目的能力。Sedgewick,p . 91

#7


7  

My previous answer was not enough accurate. As truly it was horrible :D But now I can post much more useful and correct answer.

我以前的回答不够准确。确实很可怕,但现在我可以发布更有用、更正确的答案了。


I did some additional tests. You can find it's source by the following link and reCheck it on your environment by your own: https://github.com/ukushu/DataStructuresTestsAndOther.git

我做了一些额外的测试。您可以通过以下链接找到它的源代码,并在您的环境中重新检查它:https://github.com/ukushu/DataStructuresTestsAndOther.git。

Short results:

短的结果:

  • Array need to use:

    需要使用数组:

    • So often as possible. It's fast and takes smallest RAM range for same amount information.
    • 尽可能经常。它是快速的,并以最小的RAM范围,以相同的数量信息。
    • If you know exact count of cells needed
    • 如果你知道确切的细胞计数需要。
    • If data saved in array < 85000 b
    • 如果数据保存在数组< 85000 b中。
    • If needed high Random Access speed
    • 如果需要高随机存取速度。
  • List need to use:

    列出需要使用:

    • If needed to add cells to the end of list (often)
    • 如果需要将单元格添加到列表的末尾(通常)
    • If needed to add cells in the beginning/middle of the list (NOT OFTEN)
    • 如果需要在列表的开始/中间添加单元格(不经常)
    • If data saved in array < 85000 b
    • 如果数据保存在数组< 85000 b中。
    • If needed high Random Access speed
    • 如果需要高随机存取速度。
  • LinkedList need to use:

    LinkedList需要使用:

    • If needed to add cells in the beginning/middle/end of the list (often)
    • 如果需要在列表的开头/中/结尾添加单元格(通常)
    • If needed only sequential access (forward/backward)
    • 如果只需要顺序访问(向前/向后)
    • If you need to save LARGE items, but items count is low.
    • 如果您需要保存大型项目,但是项目数量很低。
    • Better do not use for large amount of items, as it's use additional memory for links.
    • 对于大量的项目,最好不要使用它,因为它会对链接使用额外的内存。

More details:

更多的细节:

我应该什么时候使用List和LinkedList ? Interesting to know:

有趣的了解:

  1. Linked List internally is not a List in .NET. LinkedList<T>. It's even does not implement IList<T>. And that's why there are absent indexes and methods related to indexes.

    链接列表内部不是。net中的列表。LinkedList < T >。它甚至没有实现IList 。这就是为什么没有索引和方法相关的索引。

  2. LinkedList<T> is node-pointer based collection. In .NET it's in doubly linked implementation. This means that prior/next elements have link to current element. And data is fragmented -- different list objects can be located in different places of RAM. Also there will be more memory used for LinkedList<T> than for List<T> or Array.

    LinkedList 是基于节点指针的集合。在。net中,它是双向链接实现的。这意味着之前/下一个元素与当前元素有链接。数据是碎片化的——不同的列表对象可以位于RAM的不同位置。此外,用于LinkedList 的内存将比List 或数组要多。

  3. List<T> in .Net is Java's alternative of ArraList<T>. This means that this is array wrapper. So it's allocated in menory as one contiguous block of data. If allocated data size exceeds 85000 bytes, it will be allocated iside of the Large Object Heap. Depending on the size, this can lead to heap fragmentation, a mild form of memory leak. But in the same time if size < 85000 bytes -- this provides a very compact and fast-access representation in memory.

    在。net中List 是Java的另一个ArraList 。这意味着这是数组包装器。所以它在menory中被分配为一个连续的数据块。如果分配的数据大小超过了85000字节,将会分配给大对象堆的iside。根据大小不同,这可能导致堆碎片,一种轻微的内存泄漏。但与此同时,如果大小< 85000字节——这提供了一个非常紧凑和快速访问的内存表示。

  4. Single contiguous block is preferred for random access performance and memory consumption but for collections that need to change size regularly a structure such as an Array generally need to be copied to a new location whereas a linked list only needs to manage the memory for the newly inserted/deleted nodes.

    单一连续的块是首选的随机访问性能和内存消耗,但经常需要改变尺寸的集合结构数组等通常需要复制到一个新的位置,而一个链表只需要管理内存的新插入/删除节点。

#8


3  

A common circumstance to use LinkedList is like this:

使用LinkedList的一个常见情况是这样的:

Suppose you want to remove many certain strings from a list of strings with a large size, say 100,000. The strings to remove can be looked up in HashSet dic, and the list of strings is believed to contain between 30,000 to 60,000 such strings to remove.

假设您希望从一个较大的字符串列表中删除许多特定的字符串,比如100,000。要删除的字符串可以在HashSet dic中查找,字符串列表被认为包含3万到6万个这样的字符串。

Then what's the best type of List for storing the 100,000 Strings? The answer is LinkedList. If the they are stored in an ArrayList, then iterating over it and removing matched Strings whould take up to billions of operations, while it takes just around 100,000 operations by using an iterator and the remove() method.

那么,存储100,000个字符串的最佳列表类型是什么?答案是LinkedList。如果它们存储在ArrayList中,然后遍历它并删除匹配的字符串,则需要花费数十亿的操作,而使用迭代器和remove()方法只需要大约100,000个操作。

LinkedList<String> strings = readStrings();
HashSet<String> dic = readDic();
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()){
    String string = iterator.next();
    if (dic.contains(string))
    iterator.remove();
}

#9


2  

When you need built-in indexed access, sorting (and after this binary searching), and "ToArray()" method, you should use List.

当您需要内置索引访问、排序(以及在此二进制搜索之后)和“ToArray()”方法时,您应该使用List。

#10


1  

This is adapted from Tono Nam's accepted answer correcting a few wrong measurements in it.

这是根据Tono Nam的回答纠正了一些错误的测量。

The test:

测试:

static void Main()
{
    LinkedListPerformance.AddFirst_List(); // 12028 ms
    LinkedListPerformance.AddFirst_LinkedList(); // 33 ms

    LinkedListPerformance.AddLast_List(); // 33 ms
    LinkedListPerformance.AddLast_LinkedList(); // 32 ms

    LinkedListPerformance.Enumerate_List(); // 1.08 ms
    LinkedListPerformance.Enumerate_LinkedList(); // 3.4 ms

    //I tried below as fun exercise - not very meaningful, see code
    //sort of equivalent to insertion when having the reference to middle node

    LinkedListPerformance.AddMiddle_List(); // 5724 ms
    LinkedListPerformance.AddMiddle_LinkedList1(); // 36 ms
    LinkedListPerformance.AddMiddle_LinkedList2(); // 32 ms
    LinkedListPerformance.AddMiddle_LinkedList3(); // 454 ms

    Environment.Exit(-1);
}

And the code:

和代码:

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace *
{
    static class LinkedListPerformance
    {
        class Temp
        {
            public decimal A, B, C, D;

            public Temp(decimal a, decimal b, decimal c, decimal d)
            {
                A = a; B = b; C = c; D = d;
            }
        }



        static readonly int start = 0;
        static readonly int end = 123456;
        static readonly IEnumerable<Temp> query = Enumerable.Range(start, end - start).Select(temp);

        static Temp temp(int i)
        {
            return new Temp(i, i, i, i);
        }

        static void StopAndPrint(this Stopwatch watch)
        {
            watch.Stop();
            Console.WriteLine(watch.Elapsed.TotalMilliseconds);
        }

        public static void AddFirst_List()
        {
            var list = new List<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
                list.Insert(0, temp(i));

            watch.StopAndPrint();
        }

        public static void AddFirst_LinkedList()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (int i = start; i < end; i++)
                list.AddFirst(temp(i));

            watch.StopAndPrint();
        }

        public static void AddLast_List()
        {
            var list = new List<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
                list.Add(temp(i));

            watch.StopAndPrint();
        }

        public static void AddLast_LinkedList()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (int i = start; i < end; i++)
                list.AddLast(temp(i));

            watch.StopAndPrint();
        }

        public static void Enumerate_List()
        {
            var list = new List<Temp>(query);
            var watch = Stopwatch.StartNew();

            foreach (var item in list)
            {

            }

            watch.StopAndPrint();
        }

        public static void Enumerate_LinkedList()
        {
            var list = new LinkedList<Temp>(query);
            var watch = Stopwatch.StartNew();

            foreach (var item in list)
            {

            }

            watch.StopAndPrint();
        }

        //for the fun of it, I tried to time inserting to the middle of 
        //linked list - this is by no means a realistic scenario! or may be 
        //these make sense if you assume you have the reference to middle node

        //insertion to the middle of list
        public static void AddMiddle_List()
        {
            var list = new List<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
                list.Insert(list.Count / 2, temp(i));

            watch.StopAndPrint();
        }

        //insertion in linked list in such a fashion that 
        //it has the same effect as inserting into the middle of list
        public static void AddMiddle_LinkedList1()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            LinkedListNode<Temp> evenNode = null, oddNode = null;
            for (int i = start; i < end; i++)
            {
                if (list.Count == 0)
                    oddNode = evenNode = list.AddLast(temp(i));
                else
                    if (list.Count % 2 == 1)
                        oddNode = list.AddBefore(evenNode, temp(i));
                    else
                        evenNode = list.AddAfter(oddNode, temp(i));
            }

            watch.StopAndPrint();
        }

        //another hacky way
        public static void AddMiddle_LinkedList2()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start + 1; i < end; i += 2)
                list.AddLast(temp(i));
            for (int i = end - 2; i >= 0; i -= 2)
                list.AddLast(temp(i));

            watch.StopAndPrint();
        }

        //OP's original more sensible approach, but I tried to filter out
        //the intermediate iteration cost in finding the middle node.
        public static void AddMiddle_LinkedList3()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
            {
                if (list.Count == 0)
                    list.AddLast(temp(i));
                else
                {
                    watch.Stop();
                    var curNode = list.First;
                    for (var j = 0; j < list.Count / 2; j++)
                        curNode = curNode.Next;
                    watch.Start();

                    list.AddBefore(curNode, temp(i));
                }
            }

            watch.StopAndPrint();
        }
    }
}

You can see the results are in accordance with theoretical performance others have documented here. Quite clear - LinkedList<T> gains big time in case of insertions. I haven't tested for removal from the middle of list, but the result should be the same. Of course List<T> has other areas where it performs way better like O(1) random access.

您可以看到,结果与其他的理论表现一致。相当清晰的- LinkedList< t>在插入时获得了很大的时间。我还没有测试从列表中间删除,但是结果应该是相同的。当然,List 还有其他的地方,它的执行方式更像O(1)随机访问。

#11


1  

Essentially, a List<> in .NET is a wrapper over an array. A LinkedList<> is a linked list. So the question comes down to, what is the difference between an array and a linked list, and when should an array be used instead of a linked list. Probably the two most important factors in your decision of which to use would come down to:

本质上,在。net中,List<>是一个数组的包装器。一个LinkedList<>是一个链表。所以问题归结为,数组和链表之间的区别是什么,什么时候应该使用数组而不是链表。也许你决定使用的两个最重要的因素是:

  • Linked lists have much better insertion/removal performance, so long as the insertions/removals are not on the last element in the collection. This is because an array must shift all remaining elements that come after the insertion/removal point. If the insertion/removal is at the tail end of the list however, this shift is not needed (although the array may need to be resized, if its capacity is exceeded).
  • 链表有更好的插入/删除性能,只要插入/删除不在集合的最后一个元素上。这是因为数组必须改变插入/删除点之后的所有剩余元素。如果插入/删除是在列表的末尾,则不需要这种转换(尽管数组可能需要调整大小,如果超出了它的容量)。
  • Arrays have much better accessing capabilities. Arrays can be indexed into directly (in constant time). Linked lists must be traversed (linear time).
  • 数组具有更好的访问能力。数组可以直接编入索引(在常量时间内)。链接列表必须是遍历的(线性时间)。

#12


0  

Use LinkedList<> when

使用< >当LinkedList

  1. You don't know how many objects are coming through the flood gate. For example, Token Stream.
  2. 你不知道有多少物体通过了洪水门。例如,标记流。
  3. When you ONLY wanted to delete\insert at the ends.
  4. 当你只想删除\插入到结尾。

For everything else, it is better to use List<>.

对于其他所有内容,最好使用List<>。

#13


0  

So many average answers here...

这么多的平均答案……

Some linked list implementations use underlying blocks of pre allocated nodes. If they don't do this than constant time / linear time is less relevant as memory performance will be poor and cache performance even worse.

一些链表实现使用预先分配的节点的基础块。如果它们不这样做,那么随着时间的推移,它们的相关性就会降低,因为内存性能会很差,缓存性能会更差。

Use linked lists when

使用链表

1) You want thread safety. You can build better thread safe algos. Locking costs will dominate a concurrent style list.

你想要线程安全。您可以构建更好的线程安全的algos。锁定成本将主导一个并发样式列表。

2) If you have a large queue like structures and want to remove or add anywhere but the end all the time . >100K lists exists but are not that common.

2)如果你有一个很大的队列,比如结构,想要删除或添加任何地方,但总是结束。>100K列表存在,但并不常见。

#14


0  

I asked a similar question related to performance of the LinkedList collection, and discovered Steven Cleary's C# implement of Deque was a solution. Unlike the Queue collection, Deque allows moving items on/off front and back. It is similar to linked list, but with improved performance.

我问了一个类似的问题,与LinkedList集合的性能有关,发现了Steven Cleary的c#实现Deque是一个解决方案。与队列收集不同,Deque允许在前后移动项目。它与链表相似,但性能有所提高。

#15


0  

I do agree with most of the point made above. And I also agree that List looks like a more obvious choice in most of the cases.

我确实同意上面提到的大部分观点。我也同意,在大多数情况下,列表看起来是一个更明显的选择。

But, I just want to add that there are many instance where LinkedList are far better choice than List for better efficiency.

但是,我想补充的是,在很多情况下,LinkedList都是比列表更好的选择。

  1. Suppose you are traversing through the elements and you want to perform lot of insertions/deletion; LinkedList does it in linear O(n) time, whereas List does it in quadratic O(n^2) time.
  2. 假设您正在遍历元素,并且希望执行大量的插入/删除操作;LinkedList它在线性O(n)时间,而列表是否二次O(n ^ 2)时间。
  3. Suppose you want to access bigger objects again and again, LinkedList become very more useful.
  4. 假设您想一次又一次地访问较大的对象,LinkedList变得非常有用。
  5. Deque() and queue() are better implemented using LinkedList.
  6. Deque()和queue()使用LinkedList更好地实现。
  7. Increasing the size of LinkedList is much easier and better once you are dealing with many and bigger objects.
  8. 当你处理许多更大的对象时,增加LinkedList的大小会变得更容易和更好。

Hope someone would find these comments useful.

希望有人会觉得这些评论有用。

#1


101  

Edit

Please read the comments to this answer. People claim I did not do proper tests. I agree this should not be an accepted answer. As I was learning I did some tests and felt like sharing them.

请阅读下面的评论。人们声称我没有做适当的测试。我同意这不是一个公认的答案。在我学习的过程中,我做了一些测试,想要分享它们。

Original answer...

I found interesting results:

我发现了有趣的结果:

// Temporary class to show the example
class Temp
{
    public decimal A, B, C, D;

    public Temp(decimal a, decimal b, decimal c, decimal d)
    {
        A = a;            B = b;            C = c;            D = d;
    }
}

Linked list (3.9 seconds)

        LinkedList<Temp> list = new LinkedList<Temp>();

        for (var i = 0; i < 12345678; i++)
        {
            var a = new Temp(i, i, i, i);
            list.AddLast(a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

List (2.4 seconds)

        List<Temp> list = new List<Temp>(); // 2.4 seconds

        for (var i = 0; i < 12345678; i++)
        {
            var a = new Temp(i, i, i, i);
            list.Add(a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

Even if you only access data essentially it is much slower!! I say never use a linkedList.

即使你只访问数据,实际上它要慢得多!!我说永远不要使用linkedList。




Here is another comparison performing a lot of inserts (we plan on inserting an item at the middle of the list)

这里是另一个执行大量插入的比较(我们计划在列表的中间插入一个项目)

Linked List (51 seconds)

        LinkedList<Temp> list = new LinkedList<Temp>();

        for (var i = 0; i < 123456; i++)
        {
            var a = new Temp(i, i, i, i);

            list.AddLast(a);
            var curNode = list.First;

            for (var k = 0; k < i/2; k++) // In order to insert a node at the middle of the list we need to find it
                curNode = curNode.Next;

            list.AddAfter(curNode, a); // Insert it after
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

List (7.26 seconds)

        List<Temp> list = new List<Temp>();

        for (var i = 0; i < 123456; i++)
        {
            var a = new Temp(i, i, i, i);

            list.Insert(i / 2, a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

Linked List having reference of location where to insert (.04 seconds)

        list.AddLast(new Temp(1,1,1,1));
        var referenceNode = list.First;

        for (var i = 0; i < 123456; i++)
        {
            var a = new Temp(i, i, i, i);

            list.AddLast(a);
            list.AddBefore(referenceNode, a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

So only if you plan on inserting several items and you also somewhere have the reference of where you plan to insert the item then use a linked list. Just because you have to insert a lot of items it does not make it faster because searching the location where you will like to insert it takes time.

因此,只有当您计划插入多个项目时,您还可以在某个地方引用您计划插入该项目的位置,然后使用一个链表。仅仅因为你需要插入很多项,它不会使它更快,因为搜索你想插入的位置需要时间。

#2


230  

In most cases, List<T> is more useful. LinkedList<T> will have less cost when adding/removing items in the middle of the list, whereas List<T> can only cheaply add/remove at the end of the list.

在大多数情况下,List 更有用。当在列表中间添加/移除项时,LinkedList< t>的成本会更低,而list 只能在列表的末尾添加/删除。

LinkedList<T> is only at it's most efficient if you are accessing sequential data (either forwards or backwards) - random access is relatively expensive since it must walk the chain each time (hence why it doesn't have an indexer). However, because a List<T> is essentially just an array (with a wrapper) random access is fine.

LinkedList 只是在访问顺序数据(向前或向后)时效率最高,因为每次随机存取都比较昂贵,因为它每次都必须遍历链(因此它没有索引器)。但是,因为List 实际上只是一个数组(带有一个包装器),所以随机访问很好。

List<T> also offers a lot of support methods - Find, ToArray, etc; however, these are also available for LinkedList<T> with .NET 3.5/C# 3.0 via extension methods - so that is less of a factor.

List 还提供了许多支持方法——Find、ToArray等;但是,这些也可以通过扩展方法使用。net 3.5/ c# 3.0,这是一个更少的因素。

#3


182  

Thinking of a linked list as a list can be a bit misleading. It's more like a chain. In fact, in .NET, LinkedList<T> does not even implement IList<T>. There is no real concept of index in a linked list, even though it may seem there is. Certainly none of the methods provided on the class accept indexes.

把一个链表看作一个列表可能有点误导。它更像一条链。事实上,在。net中,LinkedList 甚至没有实现IList 。在一个链表中没有真正的索引概念,即使它看起来有。当然,类中提供的方法都不接受索引。

Linked lists may be singly linked, or doubly linked. This refers to whether each element in the chain has a link only to the next one (singly linked) or to both the prior/next elements (doubly linked). LinkedList<T> is doubly linked.

链接列表可能是单链接的,或者是双向链接的。这是指链中的每个元素是否只链接到下一个(单个链接)或之前/下一个元素(双链接)。LinkedList < T >是双向链。

Internally, List<T> is backed by an array. This provides a very compact representation in memory. Conversely, LinkedList<T> involves additional memory to store the bidirectional links between successive elements. So the memory footprint of a LinkedList<T> will generally be larger than for List<T> (with the caveat that List<T> can have unused internal array elements to improve performance during append operations.)

在内部,List 由一个数组支持。这在内存中提供了一个非常紧凑的表示。相反,LinkedList 包含了额外的内存来存储连续元素之间的双向链接。因此,LinkedList< t>的内存占用通常比List 更大(需要注意的是,List 可以有未使用的内部数组元素来提高append操作期间的性能)。

They have different performance characteristics too:

它们的性能也不同:

Append

  • LinkedList<T>.AddLast(item) constant time
  • LinkedList < T > .AddLast常数时间(项)
  • List<T>.Add(item) amortized constant time, linear worst case
  • 列表 .Add(项)平摊常数时间,线性最坏情况。

Prepend

  • LinkedList<T>.AddFirst(item) constant time
  • LinkedList < T > .AddFirst常数时间(项)
  • List<T>.Insert(0, item) linear time
  • < T >列表。插入(0,项)线性时间

Insertion

  • LinkedList<T>.AddBefore(node, item) constant time
  • LinkedList < T >。AddBefore节点,项目持续时间
  • LinkedList<T>.AddAfter(node, item) constant time
  • LinkedList < T >。AddAfter节点,项目持续时间
  • List<T>.Insert(index, item) linear time
  • < T >列表。插入(指数项)线性时间

Removal

  • LinkedList<T>.Remove(item) linear time
  • LinkedList < T > .Remove(项)线性时间
  • LinkedList<T>.Remove(node) constant time
  • LinkedList < T > .Remove(节点)持续的时间
  • List<T>.Remove(item) linear time
  • < T > .Remove列表(项)线性时间
  • List<T>.RemoveAt(index) linear time
  • < T > .RemoveAt列表(指数)线性时间

Count

  • LinkedList<T>.Count constant time
  • LinkedList < T >。计算常数时间
  • List<T>.Count constant time
  • < T >列表。计算常数时间

Contains

  • LinkedList<T>.Contains(item) linear time
  • LinkedList < T > .Contains(项)线性时间
  • List<T>.Contains(item) linear time
  • < T > .Contains列表(项)线性时间

Clear

  • LinkedList<T>.Clear() linear time
  • LinkedList < T > .Clear()线性时间
  • List<T>.Clear() linear time
  • < T > .Clear列表()线性时间

As you can see, they're mostly equivalent. In practice, the API of LinkedList<T> is more cumbersome to use, and details of its internal needs spill out into your code.

正如你所看到的,它们基本上是等价的。在实践中,LinkedList 的API使用起来更麻烦,其内部需求的细节会溢出到您的代码中。

However, if you need to do many insertions/removals from within a list, it offers constant time. List<T> offers linear time, as extra items in the list must be shuffled around after the insertion/removal.

但是,如果您需要从列表中执行许多插入/删除操作,它提供了常量时间。列表 提供了线性时间,因为在插入/删除之后,列表中的额外项必须被拖拽。

#4


112  

Linked lists provide very fast insertion or deletion of a list member. Each member in a linked list contains a pointer to the next member in the list so to insert a member at position i:

链表提供非常快的插入或删除列表成员。链表中的每个成员都包含一个指向列表中的下一个成员的指针,以便在position i中插入一个成员:

  • update the pointer in member i-1 to point to the new member
  • 更新成员i-1中的指针指向新成员。
  • set the pointer in the new member to point to member i
  • 设置新成员中的指针指向成员i。

The disadvantage to a linked list is that random access is not possible. Accessing a member requires traversing the list until the desired member is found.

链表的缺点是不可能随机访问。访问成员需要遍历列表,直到找到所需的成员。

#5


16  

The difference between List and LinkedList lies in their underlying implementation. List is array based collection (ArrayList). LinkedList is node-pointer based collection (LinkedListNode). On the API level usage, both of them are pretty much the same since both implement same set of interfaces such as ICollection, IEnumerable, etc.

List和LinkedList的区别在于它们的底层实现。List是基于数组的集合(ArrayList)。LinkedList是基于节点指针的集合(LinkedListNode)。在API级别的使用上,它们几乎是相同的,因为它们都实现了相同的接口集,比如ICollection、IEnumerable等。

The key difference comes when performance matter. For example, if you are implementing the list that has heavy "INSERT" operation, LinkedList outperforms List. Since LinkedList can do it in O(1) time, but List may need to expand the size of underlying array. For more information/detail you might want to read up on the algorithmic difference between LinkedList and array data structures. http://en.wikipedia.org/wiki/Linked_list and Array

关键的区别在于性能问题。例如,如果您正在实现具有重“插入”操作的列表,LinkedList将超过列表。因为LinkedList可以在O(1)时间内完成,但是列表可能需要扩展底层数组的大小。要了解更多信息/细节,您可能需要了解LinkedList和数组数据结构之间的算法差异。http://en.wikipedia.org/wiki/Linked_list和数组

Hope this help,

希望这个有帮助,

#6


10  

The primary advantage of linked lists over arrays is that the links provide us with the capability to rearrange the items efficiently. Sedgewick, p. 91

链表与数组的主要优点是,这些链接为我们提供了有效地重新排列项目的能力。Sedgewick,p . 91

#7


7  

My previous answer was not enough accurate. As truly it was horrible :D But now I can post much more useful and correct answer.

我以前的回答不够准确。确实很可怕,但现在我可以发布更有用、更正确的答案了。


I did some additional tests. You can find it's source by the following link and reCheck it on your environment by your own: https://github.com/ukushu/DataStructuresTestsAndOther.git

我做了一些额外的测试。您可以通过以下链接找到它的源代码,并在您的环境中重新检查它:https://github.com/ukushu/DataStructuresTestsAndOther.git。

Short results:

短的结果:

  • Array need to use:

    需要使用数组:

    • So often as possible. It's fast and takes smallest RAM range for same amount information.
    • 尽可能经常。它是快速的,并以最小的RAM范围,以相同的数量信息。
    • If you know exact count of cells needed
    • 如果你知道确切的细胞计数需要。
    • If data saved in array < 85000 b
    • 如果数据保存在数组< 85000 b中。
    • If needed high Random Access speed
    • 如果需要高随机存取速度。
  • List need to use:

    列出需要使用:

    • If needed to add cells to the end of list (often)
    • 如果需要将单元格添加到列表的末尾(通常)
    • If needed to add cells in the beginning/middle of the list (NOT OFTEN)
    • 如果需要在列表的开始/中间添加单元格(不经常)
    • If data saved in array < 85000 b
    • 如果数据保存在数组< 85000 b中。
    • If needed high Random Access speed
    • 如果需要高随机存取速度。
  • LinkedList need to use:

    LinkedList需要使用:

    • If needed to add cells in the beginning/middle/end of the list (often)
    • 如果需要在列表的开头/中/结尾添加单元格(通常)
    • If needed only sequential access (forward/backward)
    • 如果只需要顺序访问(向前/向后)
    • If you need to save LARGE items, but items count is low.
    • 如果您需要保存大型项目,但是项目数量很低。
    • Better do not use for large amount of items, as it's use additional memory for links.
    • 对于大量的项目,最好不要使用它,因为它会对链接使用额外的内存。

More details:

更多的细节:

我应该什么时候使用List和LinkedList ? Interesting to know:

有趣的了解:

  1. Linked List internally is not a List in .NET. LinkedList<T>. It's even does not implement IList<T>. And that's why there are absent indexes and methods related to indexes.

    链接列表内部不是。net中的列表。LinkedList < T >。它甚至没有实现IList 。这就是为什么没有索引和方法相关的索引。

  2. LinkedList<T> is node-pointer based collection. In .NET it's in doubly linked implementation. This means that prior/next elements have link to current element. And data is fragmented -- different list objects can be located in different places of RAM. Also there will be more memory used for LinkedList<T> than for List<T> or Array.

    LinkedList 是基于节点指针的集合。在。net中,它是双向链接实现的。这意味着之前/下一个元素与当前元素有链接。数据是碎片化的——不同的列表对象可以位于RAM的不同位置。此外,用于LinkedList 的内存将比List 或数组要多。

  3. List<T> in .Net is Java's alternative of ArraList<T>. This means that this is array wrapper. So it's allocated in menory as one contiguous block of data. If allocated data size exceeds 85000 bytes, it will be allocated iside of the Large Object Heap. Depending on the size, this can lead to heap fragmentation, a mild form of memory leak. But in the same time if size < 85000 bytes -- this provides a very compact and fast-access representation in memory.

    在。net中List 是Java的另一个ArraList 。这意味着这是数组包装器。所以它在menory中被分配为一个连续的数据块。如果分配的数据大小超过了85000字节,将会分配给大对象堆的iside。根据大小不同,这可能导致堆碎片,一种轻微的内存泄漏。但与此同时,如果大小< 85000字节——这提供了一个非常紧凑和快速访问的内存表示。

  4. Single contiguous block is preferred for random access performance and memory consumption but for collections that need to change size regularly a structure such as an Array generally need to be copied to a new location whereas a linked list only needs to manage the memory for the newly inserted/deleted nodes.

    单一连续的块是首选的随机访问性能和内存消耗,但经常需要改变尺寸的集合结构数组等通常需要复制到一个新的位置,而一个链表只需要管理内存的新插入/删除节点。

#8


3  

A common circumstance to use LinkedList is like this:

使用LinkedList的一个常见情况是这样的:

Suppose you want to remove many certain strings from a list of strings with a large size, say 100,000. The strings to remove can be looked up in HashSet dic, and the list of strings is believed to contain between 30,000 to 60,000 such strings to remove.

假设您希望从一个较大的字符串列表中删除许多特定的字符串,比如100,000。要删除的字符串可以在HashSet dic中查找,字符串列表被认为包含3万到6万个这样的字符串。

Then what's the best type of List for storing the 100,000 Strings? The answer is LinkedList. If the they are stored in an ArrayList, then iterating over it and removing matched Strings whould take up to billions of operations, while it takes just around 100,000 operations by using an iterator and the remove() method.

那么,存储100,000个字符串的最佳列表类型是什么?答案是LinkedList。如果它们存储在ArrayList中,然后遍历它并删除匹配的字符串,则需要花费数十亿的操作,而使用迭代器和remove()方法只需要大约100,000个操作。

LinkedList<String> strings = readStrings();
HashSet<String> dic = readDic();
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()){
    String string = iterator.next();
    if (dic.contains(string))
    iterator.remove();
}

#9


2  

When you need built-in indexed access, sorting (and after this binary searching), and "ToArray()" method, you should use List.

当您需要内置索引访问、排序(以及在此二进制搜索之后)和“ToArray()”方法时,您应该使用List。

#10


1  

This is adapted from Tono Nam's accepted answer correcting a few wrong measurements in it.

这是根据Tono Nam的回答纠正了一些错误的测量。

The test:

测试:

static void Main()
{
    LinkedListPerformance.AddFirst_List(); // 12028 ms
    LinkedListPerformance.AddFirst_LinkedList(); // 33 ms

    LinkedListPerformance.AddLast_List(); // 33 ms
    LinkedListPerformance.AddLast_LinkedList(); // 32 ms

    LinkedListPerformance.Enumerate_List(); // 1.08 ms
    LinkedListPerformance.Enumerate_LinkedList(); // 3.4 ms

    //I tried below as fun exercise - not very meaningful, see code
    //sort of equivalent to insertion when having the reference to middle node

    LinkedListPerformance.AddMiddle_List(); // 5724 ms
    LinkedListPerformance.AddMiddle_LinkedList1(); // 36 ms
    LinkedListPerformance.AddMiddle_LinkedList2(); // 32 ms
    LinkedListPerformance.AddMiddle_LinkedList3(); // 454 ms

    Environment.Exit(-1);
}

And the code:

和代码:

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace *
{
    static class LinkedListPerformance
    {
        class Temp
        {
            public decimal A, B, C, D;

            public Temp(decimal a, decimal b, decimal c, decimal d)
            {
                A = a; B = b; C = c; D = d;
            }
        }



        static readonly int start = 0;
        static readonly int end = 123456;
        static readonly IEnumerable<Temp> query = Enumerable.Range(start, end - start).Select(temp);

        static Temp temp(int i)
        {
            return new Temp(i, i, i, i);
        }

        static void StopAndPrint(this Stopwatch watch)
        {
            watch.Stop();
            Console.WriteLine(watch.Elapsed.TotalMilliseconds);
        }

        public static void AddFirst_List()
        {
            var list = new List<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
                list.Insert(0, temp(i));

            watch.StopAndPrint();
        }

        public static void AddFirst_LinkedList()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (int i = start; i < end; i++)
                list.AddFirst(temp(i));

            watch.StopAndPrint();
        }

        public static void AddLast_List()
        {
            var list = new List<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
                list.Add(temp(i));

            watch.StopAndPrint();
        }

        public static void AddLast_LinkedList()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (int i = start; i < end; i++)
                list.AddLast(temp(i));

            watch.StopAndPrint();
        }

        public static void Enumerate_List()
        {
            var list = new List<Temp>(query);
            var watch = Stopwatch.StartNew();

            foreach (var item in list)
            {

            }

            watch.StopAndPrint();
        }

        public static void Enumerate_LinkedList()
        {
            var list = new LinkedList<Temp>(query);
            var watch = Stopwatch.StartNew();

            foreach (var item in list)
            {

            }

            watch.StopAndPrint();
        }

        //for the fun of it, I tried to time inserting to the middle of 
        //linked list - this is by no means a realistic scenario! or may be 
        //these make sense if you assume you have the reference to middle node

        //insertion to the middle of list
        public static void AddMiddle_List()
        {
            var list = new List<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
                list.Insert(list.Count / 2, temp(i));

            watch.StopAndPrint();
        }

        //insertion in linked list in such a fashion that 
        //it has the same effect as inserting into the middle of list
        public static void AddMiddle_LinkedList1()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            LinkedListNode<Temp> evenNode = null, oddNode = null;
            for (int i = start; i < end; i++)
            {
                if (list.Count == 0)
                    oddNode = evenNode = list.AddLast(temp(i));
                else
                    if (list.Count % 2 == 1)
                        oddNode = list.AddBefore(evenNode, temp(i));
                    else
                        evenNode = list.AddAfter(oddNode, temp(i));
            }

            watch.StopAndPrint();
        }

        //another hacky way
        public static void AddMiddle_LinkedList2()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start + 1; i < end; i += 2)
                list.AddLast(temp(i));
            for (int i = end - 2; i >= 0; i -= 2)
                list.AddLast(temp(i));

            watch.StopAndPrint();
        }

        //OP's original more sensible approach, but I tried to filter out
        //the intermediate iteration cost in finding the middle node.
        public static void AddMiddle_LinkedList3()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
            {
                if (list.Count == 0)
                    list.AddLast(temp(i));
                else
                {
                    watch.Stop();
                    var curNode = list.First;
                    for (var j = 0; j < list.Count / 2; j++)
                        curNode = curNode.Next;
                    watch.Start();

                    list.AddBefore(curNode, temp(i));
                }
            }

            watch.StopAndPrint();
        }
    }
}

You can see the results are in accordance with theoretical performance others have documented here. Quite clear - LinkedList<T> gains big time in case of insertions. I haven't tested for removal from the middle of list, but the result should be the same. Of course List<T> has other areas where it performs way better like O(1) random access.

您可以看到,结果与其他的理论表现一致。相当清晰的- LinkedList< t>在插入时获得了很大的时间。我还没有测试从列表中间删除,但是结果应该是相同的。当然,List 还有其他的地方,它的执行方式更像O(1)随机访问。

#11


1  

Essentially, a List<> in .NET is a wrapper over an array. A LinkedList<> is a linked list. So the question comes down to, what is the difference between an array and a linked list, and when should an array be used instead of a linked list. Probably the two most important factors in your decision of which to use would come down to:

本质上,在。net中,List<>是一个数组的包装器。一个LinkedList<>是一个链表。所以问题归结为,数组和链表之间的区别是什么,什么时候应该使用数组而不是链表。也许你决定使用的两个最重要的因素是:

  • Linked lists have much better insertion/removal performance, so long as the insertions/removals are not on the last element in the collection. This is because an array must shift all remaining elements that come after the insertion/removal point. If the insertion/removal is at the tail end of the list however, this shift is not needed (although the array may need to be resized, if its capacity is exceeded).
  • 链表有更好的插入/删除性能,只要插入/删除不在集合的最后一个元素上。这是因为数组必须改变插入/删除点之后的所有剩余元素。如果插入/删除是在列表的末尾,则不需要这种转换(尽管数组可能需要调整大小,如果超出了它的容量)。
  • Arrays have much better accessing capabilities. Arrays can be indexed into directly (in constant time). Linked lists must be traversed (linear time).
  • 数组具有更好的访问能力。数组可以直接编入索引(在常量时间内)。链接列表必须是遍历的(线性时间)。

#12


0  

Use LinkedList<> when

使用< >当LinkedList

  1. You don't know how many objects are coming through the flood gate. For example, Token Stream.
  2. 你不知道有多少物体通过了洪水门。例如,标记流。
  3. When you ONLY wanted to delete\insert at the ends.
  4. 当你只想删除\插入到结尾。

For everything else, it is better to use List<>.

对于其他所有内容,最好使用List<>。

#13


0  

So many average answers here...

这么多的平均答案……

Some linked list implementations use underlying blocks of pre allocated nodes. If they don't do this than constant time / linear time is less relevant as memory performance will be poor and cache performance even worse.

一些链表实现使用预先分配的节点的基础块。如果它们不这样做,那么随着时间的推移,它们的相关性就会降低,因为内存性能会很差,缓存性能会更差。

Use linked lists when

使用链表

1) You want thread safety. You can build better thread safe algos. Locking costs will dominate a concurrent style list.

你想要线程安全。您可以构建更好的线程安全的algos。锁定成本将主导一个并发样式列表。

2) If you have a large queue like structures and want to remove or add anywhere but the end all the time . >100K lists exists but are not that common.

2)如果你有一个很大的队列,比如结构,想要删除或添加任何地方,但总是结束。>100K列表存在,但并不常见。

#14


0  

I asked a similar question related to performance of the LinkedList collection, and discovered Steven Cleary's C# implement of Deque was a solution. Unlike the Queue collection, Deque allows moving items on/off front and back. It is similar to linked list, but with improved performance.

我问了一个类似的问题,与LinkedList集合的性能有关,发现了Steven Cleary的c#实现Deque是一个解决方案。与队列收集不同,Deque允许在前后移动项目。它与链表相似,但性能有所提高。

#15


0  

I do agree with most of the point made above. And I also agree that List looks like a more obvious choice in most of the cases.

我确实同意上面提到的大部分观点。我也同意,在大多数情况下,列表看起来是一个更明显的选择。

But, I just want to add that there are many instance where LinkedList are far better choice than List for better efficiency.

但是,我想补充的是,在很多情况下,LinkedList都是比列表更好的选择。

  1. Suppose you are traversing through the elements and you want to perform lot of insertions/deletion; LinkedList does it in linear O(n) time, whereas List does it in quadratic O(n^2) time.
  2. 假设您正在遍历元素,并且希望执行大量的插入/删除操作;LinkedList它在线性O(n)时间,而列表是否二次O(n ^ 2)时间。
  3. Suppose you want to access bigger objects again and again, LinkedList become very more useful.
  4. 假设您想一次又一次地访问较大的对象,LinkedList变得非常有用。
  5. Deque() and queue() are better implemented using LinkedList.
  6. Deque()和queue()使用LinkedList更好地实现。
  7. Increasing the size of LinkedList is much easier and better once you are dealing with many and bigger objects.
  8. 当你处理许多更大的对象时,增加LinkedList的大小会变得更容易和更好。

Hope someone would find these comments useful.

希望有人会觉得这些评论有用。