C#List从结尾删除,真的是O(n)?

时间:2011-03-22 18:45:07

标签: c# big-o

我已经阅读了几篇文章,声明List.RemoveAt()处于O(n)时间。

如果我这样做:

var myList = new List<int>();

/* Add many ints to the list here. */

// Remove item at end of list:
myList.RemoveAt(myList.Count - 1); // Does this line run in O(n) time?

从列表末尾删除应该是O(1),因为它只需要递减列表计数。

我是否需要编写自己的类来执行此操作,或者删除C#列表末尾的项目是否已在O(1)时间内执行?

5 个答案:

答案 0 :(得分:24)

通常List<T>::RemoveAt是O(N),因为需要在索引向上移动数组中的一个插槽之后。但是对于从列表末尾删除的特定情况,不需要移位,因此O(1)

答案 1 :(得分:5)

删除最后一项实际上将是O(1)操作,因为仅在这种情况下List不会移动数组中的下一项。这是来自Reflector的代码:

this._size--;
if (index < this._size) // this statement is false if index equals last index in List
{
    Array.Copy(this._items, index + 1, this._items, index, this._size - index);
}
this._items[this._size] = default(T);

答案 2 :(得分:2)

这应该给你一个想法

    public void RemoveAt(int index) {
        if ((uint)index >= (uint)_size) { 
            ThrowHelper.ThrowArgumentOutOfRangeException(); 
        }
        _size--; 
        if (index < _size) {
            Array.Copy(_items, index + 1, _items, index, _size - index);
        }
        _items[_size] = default(T); 
        _version++;
    } 

答案 3 :(得分:0)

渐近地说,O(N)是方法本身的最坏情况时间复杂度,其中N是计数。它的表现不会比这差。

实际上,它将是O(N-I)的顺序(忽略恒定的时间开销),其中I是索引。这是可以推论的,因为超出给定索引I的所有项目都需要移到列表中分别位于它们之前的位置。

要直观地看到这一点,如果N为100,索引为99(最后一个元素),则没有元素需要“移动”,仅删除最后一个元素即可(或者只是在不更改大小的情况下减少了计数)数据结构)。

类似地,当N为100且索引为0(第一个元素)时,必须进行99个移位。

运行以下代码,亲自看看:

int size = 1000000;
var list1 = new List<int>();
var list2 = new List<int>();

for (int i = 0; i < size; i++)
{
    list1.Add(i);
    list2.Add(i);
}

var sw = Stopwatch.StartNew();
for (int i = 0; i < size; i++)
{
    list1.RemoveAt(size-1);
    list1.Add(0);
}
sw.Stop();
Console.WriteLine("Time elapsed: {0}", sw.ElapsedMilliseconds);

sw = Stopwatch.StartNew();
for (int i = 0; i < size; i++)
{
    list2.RemoveAt(0);
    list2.Add(0);
}
sw.Stop();

Console.WriteLine("Time elapsed: {0}", sw.ElapsedMilliseconds);

答案 4 :(得分:-2)

在我看来,如果这实际上与您的申请相关,那么您可以在比提出问题所花费的时间更短的时间内对其进行测量。现在你至少有两个相互矛盾的答案,所以无论如何你都要测试它。

我想说的是,除非MSDN文档说列表末尾的项目的removeAt是O(1),否则你真的不能指望它以这种方式工作,它可能会改变在任何给定的.NET更新中。就此而言,对于所有人而言,不同类型的行为可能会有所不同。

如果List是要使用的“自然”数据结构,则使用它。如果从列表中删除项目最终成为您的分析的热点,那么也许是时候实现自己的类了。