根据the MSDN documentation on the List<T>.Clear
method:
此方法是O(n)操作, 其中n是计数。
为什么O(n)?我问,因为我认为只需在内部分配一个新的List<T>
数组即可完成清除T[]
。没有其他类可以引用这个数组,所以我没有看到这种方法的危害。
现在,也许这是一个愚蠢的问题......正在分配T[]
数组本身O(n)?出于某种原因,我不会这么想;但也许是(我现在缺少一个C.S.学位?)。如果是这样,我想这可以解释它,因为根据上面引用的相同文档,列表的容量保持不变,这意味着需要构建一个相同大小的数组。
(然而,这似乎不是正确的解释,因为文档应该说“其中n是容量” - 不 { {1}} *)。
我只是怀疑这个方法,而不是分配一个新的数组,将当前的所有元素清零;而且我很想知道为什么会这样。
* Hans Passant在对LukeH's answer的评论中指出文档是正确的。 Count
仅将Clear
中设置的元素清零;它不需要将所有元素“重新归零”。
答案 0 :(得分:7)
据我所知,当前实现只在其内部T[]
数组上调用Array.Clear
,而Array.Clear
是一个O(n)进程。 (正如Hans在评论中指出的那样,MSDN文档是正确的,在这种情况下n
是列表的Count
,而不是Capacity
。)
但是,即使它只在内部分配一个新的T[]
数组,那仍然是一个O(n)进程,因为分配一个大小为n
的数组涉及初始化所有n
元素为零/空/默认状态。
当然,没有什么可以阻止某种内部欺骗,其中阵列可以用0或42或其他任何长度进行初始化,然后根据需要在运行中再次自动扩展,从而摊销整体O(n)成本
答案 1 :(得分:6)
因为List<T>.Clear()
的实现会在列表的backign数组上调用Array.Clear()
,并且根据documentation该方法将该数组的所有元素设置为null
。< / p>
我猜想清除现有数组而不是创建新数组的原因是.NET团队确定清除现有数组而不是分配新数组更有效。分配新阵列也需要时间/内存,所以这是一种权衡,试图针对常见的使用场景进行优化。
答案 2 :(得分:0)
List<T>.Clear()
调用Array.Clear()
,如下所示:
public virtual void Clear()
{
if (this._size > 0)
{
Array.Clear(this._items, 0, this._size);
this._size = 0;
}
this._version++;
}
反过来,Array.Clear()
调用一个外部函数,它将数组的元素归零为O(n):
[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern void Clear(Array array, int index, int length);
答案 3 :(得分:0)
我从另一个角度提出了这个问题,这里没有回答。我当时以为应该是O(1),因为不需要分配,只需要更改Count标志/指针,因此将每个元素(不再可以访问)重置为默认值看起来很浪费,我想知道为什么要这样做。 / p>
当然,答案是这将适用于ValueTypes / structs,而不适用于类。甚至应该从List的私有数组中取消引用后者,否则它们将不符合垃圾收集的条件。
注意n是Count,而不是Capacity,因为List始终保持一个合约,无论哪些元素不可访问,该合约也都没有值。因此,“计数”和“容量”之间的元素可能从未设置过,或者在删除后已经重新设置。
但是,对于结构体而言,此重置非常浪费,在这种情况下,Clear()可以为O(1)。因此,标准库(现在,Microsoft正在改善C#的性能)中有一个空间用于IList,其中T:struct具有List <>的所有功能以及O(1)Clear()实现。
关于OP分配新的私有数组的建议:首先,您已经具有该选项,如果您要的是此选项,则只需新建List即可。其次,正如LukeH所说,分配是O(n),因为它意味着初始化/重置。第三,比较遍历已分配列表/数组的O(n)与新分配(和取消分配)需要花费的时间是非常棘手的。
答案 4 :(得分:-1)
List<T>
列表包含一些对象。分配新的List<T>
并没有消除旧列表中的对象,因此它不是clear
操作。
操作clear
执行线性一次性遍历列表,逐个清除所有元素。由于有n
个元素,因此需要O(n)
次。
分配T[]
取决于是否指定了大小。如果指定了大小,则必须为每个元素留出内存,或至少为该元素指定每个指针。因此需要O(n)
。但是,如果我们只是初始化T[]
的指针,则需要O(1)
时间。
P.S。 CS学位并不自动意味着你知道(或记住)这些东西......伤心,但是,真的。缺乏CS学位并不是有害的。