list.RemoveAt(0)的通用列表有多贵?

时间:2011-05-18 23:02:53

标签: c# .net

C#,. NET4。

我们有一些性能关键代码导致了一些问题。它是一种经过修改的队列,实际上是由List支持的。我想知道在索引0处删除元素是多么昂贵。想到的问题是:

  • 根据List的备份方式,在RemoveAt()之后是否会发生任何内存分配/解除分配,以补偿列表的新大小?我知道,例如,调整阵列大小可能很昂贵(相对而言)
  • 我总是想象列表的行为类似于链接列表,这样在零位置删除元素就意味着只需将列表开头参考从前一个零元素调整为曾经是第一个元素(但是现在是第一个元素)。但是,我的“想象力”和现实并不总是一致的。

我一直认为RemovedAt对于列表是O(1)。是这样的吗?

3 个答案:

答案 0 :(得分:23)

List<T>由一个简单数组支持,另外还有一个size字段,表示该数组的哪个部分实际上在使用中。 (为了未来的增长)。 除非您添加太多元素或调用TrimExcess,否则不会调整数组的大小。

RemoveO(n),因为它需要将列表的其余部分向下移动一个。


相反,您可以使用LinkedList<T>(除非您使用随机访问),或编写自己的列表来跟踪前面的空白部分。

答案 1 :(得分:9)

是O(n)。它甚至在MSDN上都这么说。

  

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

答案 2 :(得分:2)

据我所知,它应该是一个O( n )操作。在内部,它使用Array.Copy(这是一个O( n )操作)将0之后的元素复制回列表的后备数组中。来自Reflector:

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

因此,对于任何有效的数组索引i,它将i + 1中的所有后续元素复制到i。