C# List删除元素的性能优化

背景

X上闲逛发现这样一个post
image

简单翻译一下,就是说如果针对无序数组(顺序不重要),要删除其中某个元素,比起费劲的移动很多元素,可以把要删除的元素和最后一个元素交换,然后减小数组的长度即可。

然后我看到回复中提到这样一个PR,针对dotnet runtime

github PR地址:https://github.com/dotnet/runtime/pull/106581/commits/28f434c3f3415181901a803985d05b19b0d18107

方便观看,我直接截图贴在这里:
image

作者是Stephen Toub,.NET team的开发者
博客地址:https://devblogs.microsoft.com/dotnet/author/toub/

分析

上图我们可以看到这个优化就是文章开头提到的方法,将list.RemoveAt(targetIndex)优化,
先与最后一个元素交换list[targetIndex] = list[^1]
然后list.RemoveAt(lastIndex)

那么二者到底有何差异?
那就得看RemoveAt的源码了

RemoveAt源码

源码地址:https://github.com/microsoft/referencesource/blob/master/mscorlib/system/collections/generic/list.cs#L877

此处方便查看,我直接贴出来:

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

看源码,流程是这样的
因为是移除某个index元素,list的size必然会少一个,所以首先size--
正常我们指定某个index,那么将会进行Array.Copy操作,我们可以看到这个方法有5个参数,参数意义见:

public static void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
{
}

我们可以看到sourceArray 和 destinationArray其实都是当前数组_items
Copy之后,最后一个元素必然空着了,所以会把最后一个元素置为泛型目标的默认值 _items[_size] = default(T);

示意如下,现在小学生都能理解
image

代码如此,回到刚才的问题,list.RemoveAt(lastIndex)的时候,由于size--,所以不会进入if代码块,所以也不会发生Array.Copy操作。

posted @   talentzemin  阅读(125)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示