编程语言
首页 > 编程语言> > 优化列表删除元素操作 (C#)

优化列表删除元素操作 (C#)

作者:互联网

边遍历边删除, 前几天面试的时候被问到了这个问题。

今天研究了一下。

当时的解法是定义EndIndex作为结束标识,默认等于列表的Count

在for循环中不以列表的Count作为结束标识,而是使用EndIndex作为结束标识。

在检测到需要被删除的元素时,将该元素与尾部元素(EndIndex-1对应的元素)交换,同时不自增遍历的标识 i 且对EndIndex做自减操作。

这样就可以以列表的 [0, EndIndex ) 作为遍历结果。

不过面试官似乎对这种做法不太满意。因为这样会破坏原有列表的顺序,也不算真正的删除。

搜索了一下发现比较主流的做法是倒叙对List进行遍历(因为倒着遍历即使把元素删除了也不会影响接下来要遍历的元素),然后通过RemoveAt删除对应的元素。

不过在 C#的源码中(RemoveAt (microsoft.com)

可以看到每一次调用 RemoveAt 都会调用一次 Array.Copy 方法。

简单地测试后有以下结果 (不代表绝对时间,仅作为两者间耗时的比例参考)

在数组元素数量比较小的时候 Array.Copy 与 for循环的效率差别不大。且最佳情况时,Copy方法的效率是for的10倍左右。

而上面也提到了RemoveAt方法在每一次调用的时候,都会调用Copy方法,相当于做10%的for循环遍历。(比较好的情况下)

那也就是说, 在要被删除的数量大于10个的时候,使用 EndIndex标记循环会更加高效一些。

同时如果需要返回值的话,也可以使用List.GetRange 方法。

在实际测试之后,有以下结果(包含GetRange )

可以看到在绝大部分情况下,多次RemoveAt的效率都不如先交换后GetRange 

所以在删除元素的时候,如果删除的元素数量比较多,且也不是那么在意元素循序,我们可以选择交换元素后GetRage的方法来提高效率。

备注:在随后的测试中发现,即使在意列表顺序,在GetRange后调用Sort也会比倒叙RemoveAt快。

 

List.GetRange的位置:GetRange (microsoft.com)

 

标签:EndIndex,遍历,删除,C#,元素,列表,GetRange,RemoveAt
来源: https://www.cnblogs.com/LaNashTT/p/16341097.html