List.Insert是否有任何性能损失?

时间:2013-09-03 08:15:22

标签: c# list time-complexity

给出一个清单:

List<object> SomeList = new List<object>();

做:

SomeList.Insert(i, val);

Vs以上。

SomeList.Add(val);

是否有任何性能损失?如果是的话,它取决于:
  - i - 插入索引
  - SomeList.Count - 列表的大小

7 个答案:

答案 0 :(得分:19)

  

List类是ArrayList类的通用等价物。它使用一个数组实现IList通用接口,该数组的大小根据需要动态增加。

source

意味着内部数据存储为一个数组,因此很可能执行insert它需要移动所有元素以腾出空间,因此其复杂性为O(N),虽然add是(摊销的)常数时间O(1)操作,但

摘要 - 是的,它几乎总是会变慢,而且列表越大,它就越慢。

答案 1 :(得分:10)

如有疑问,请进行实证实验:

 List<object> SomeList = new List<object>();

        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (var i = 0; i < 100000; i++)
            SomeList.Insert(0, String.Empty);
        sw.Stop();
        Console.WriteLine(sw.Elapsed.TotalMilliseconds);
        sw.Reset();

        SomeList = new List<object>();
        sw.Start();
        for (var i = 0; i < 100000; i++)
            SomeList.Add(String.Empty);
        sw.Stop();
        Console.WriteLine(sw.Elapsed.TotalMilliseconds);

插件在我的机器上需要2800毫秒;添加需要0.8毫秒。所以是的,Insert的性能要差得多。

答案 2 :(得分:3)

我意识到这已经得到了彻底的解答,但我想指出这些信息可以在MSDN文档中找到。

The documentation for List<T>.Insert()州:

此方法是O(n)操作,其中n为Count。

The documentation for List<T>.Add()州:

如果Count小于Capacity,则此方法为O(1)操作。如果需要增加容量以容纳新元素,则此方法将成为O(n)操作,其中n为Count。

如果您碰巧提出这个问题,因为您希望频繁添加到列表的前面,那么要使用的相应数据结构是{{ 3}}

Deque在这里提供了一个很好的Deque实现:Stephen Cleary

答案 3 :(得分:2)

我的第一个想法是“是的,存在性能损失,因为Insert需要将列表中的所有项目移动到一个插槽中以便为新项目腾出空间” - 但后来我更仔细地阅读了这个问题。所以:

一般情况下Insert需要(可能很多)更多时间,因为它需要移动列表中已有的所有项目以便为新项目腾出空间,所以它是一个O (n)对列表长度的操作(如果列表已满足容量,则还需要调整大小,但这仍然是O(n)操作)。另一方面,Add只需附加新项而无需移动任何内容,因此速度更快 - O(1)操作(除非列表需要调整大小,如上所述)。

在此具体示例中,列表为空时开头为空,不会有任何性能差异。

当然所有这些都没有实际意义,因为你应该根据你的意图选择方法,除非你有记录在案的性能问题。

答案 4 :(得分:2)

对于一个空列表,它没有什么不同。

但是对于其他任何东西,它必须更慢*因为要在前面插入,整个后备阵列需要向右移动一个。

* Add导致Capacity增加的地方除外。

答案 5 :(得分:1)

当然可以。

由于List<T>由数组支持,因此要在列表开头插入的任何操作都必须移动(或复制)数组的所有其他元素。无论列表中的项目数是多少,添加到列表末尾的操作都将以固定时间发生。

答案 6 :(得分:1)

我建立在Pattermiester的性能测试之上。当我想到插入时,我想到了一个数组,要添加到数组中,必须指定要插入的索引。进行Add(0,object)似乎很不直观。另外,在进行性能测试时,始终要先创建一次扔掉。有时所花费的时间比实际需要的时间长。

结果

2.282 - Throw Away Run
2.6847 - List Insert By Index without Capacity
10544.9766 - List Insert At Index 0 without Capacity
1.8426 - List Add without Capacity
2.0835 - List Insert By Index with Capacity
1.4952 - List Add with Capacity
9323.699 - List Insert at Index 0 with Capacity

代码

        var size = 200000;
        //First test sometimes has a bad count
        List<object> SomeList = new List<object>();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (var i = 0; i < size; i++)
            SomeList.Insert(i, String.Empty);
        sw.Stop();
        Console.WriteLine(sw.Elapsed.TotalMilliseconds + " - Throw Away Run");
        sw.Reset();

        SomeList = new List<object>();
        sw = new Stopwatch();
        sw.Start();
        for (var i = 0; i < size ; i++)
            SomeList.Insert(i, String.Empty);
        sw.Stop();
        Console.WriteLine(sw.Elapsed.TotalMilliseconds+" - List Insert By Index without Capacity");
        sw.Reset();

        SomeList = new List<object>();
        sw = new Stopwatch();
        sw.Start();
        for (var i = 0; i < size; i++)
            SomeList.Insert(0, String.Empty);
        sw.Stop();
        Console.WriteLine(sw.Elapsed.TotalMilliseconds + " - List Insert At Index 0 without Capacity");
        sw.Reset();

        SomeList = new List<object>();
        sw.Start();
        for (var i = 0; i < size; i++)
            SomeList.Add(String.Empty);
        sw.Stop();
        Console.WriteLine(sw.Elapsed.TotalMilliseconds+" - List Add without Capacity");
        sw.Reset();

        SomeList = new List<object>(size);
        sw = new Stopwatch();
        sw.Start();
        for (var i = 0; i < size; i++)
            SomeList.Insert(i, String.Empty);
        sw.Stop();
        Console.WriteLine(sw.Elapsed.TotalMilliseconds+" - List Insert By Index with Capacity");
        sw.Reset();

        SomeList = new List<object>(size);
        sw.Start();
        for (var i = 0; i < size; i++)
            SomeList.Add(String.Empty);
        sw.Stop();
        Console.WriteLine(sw.Elapsed.TotalMilliseconds+" - List Add with Capacity");
        sw.Reset();

        SomeList = new List<object>(size);
        sw = new Stopwatch();
        sw.Start();
        for (var i = 0; i < size; i++)
            SomeList.Insert(0, String.Empty);
        sw.Stop();
        Console.WriteLine(sw.Elapsed.TotalMilliseconds + " - List Insert at Index 0 with Capacity");

因此,看来Add比插入的性能要好一些。但是,如果您使用Insert(0,“”),那么肯定会降低性能。如果要获得最佳性能,则要使用容量。