给出一个清单:
List<object> SomeList = new List<object>();
做:
SomeList.Insert(i, val);
Vs以上。
SomeList.Add(val);
是否有任何性能损失?如果是的话,它取决于:
- i
- 插入索引
- SomeList.Count
- 列表的大小
答案 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,“”),那么肯定会降低性能。如果要获得最佳性能,则要使用容量。