C# List删除元素的性能优化
背景
X上闲逛发现这样一个post
简单翻译一下,就是说如果针对无序数组(顺序不重要),要删除其中某个元素,比起费劲的移动很多元素,可以把要删除的元素和最后一个元素交换,然后减小数组的长度即可。
然后我看到回复中提到这样一个PR,针对dotnet runtime
github PR地址:https://github.com/dotnet/runtime/pull/106581/commits/28f434c3f3415181901a803985d05b19b0d18107
方便观看,我直接截图贴在这里:
作者是Stephen Toub,.NET team的开发者
博客地址:https://devblogs.microsoft.com/dotnet/author/toub/
分析
上图我们可以看到这个优化就是文章开头提到的方法,将list.RemoveAt(targetIndex)
优化,
先与最后一个元素交换list[targetIndex] = list[^1]
然后list.RemoveAt(lastIndex)
那么二者到底有何差异?
那就得看RemoveAt的源码了
RemoveAt源码
此处方便查看,我直接贴出来:
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);
示意如下,现在小学生都能理解
代码如此,回到刚才的问题,list.RemoveAt(lastIndex)
的时候,由于size--
,所以不会进入if代码块,所以也不会发生Array.Copy
操作。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)