找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 5|回复: 0

selfCardList.Sort((a,b)=>b.Weight.CompareTo(a.Weight)); c#内部是如何实现的?

[复制链接]

29

主题

2

回帖

296

积分

管理员

积分
296
发表于 19 小时前 | 显示全部楼层 |阅读模式
selfCardList.Sort((a,b)=>b.Weight.CompareTo(a.Weight)); 时,C#(.NET)内部经历了一个三层调用链,并最终使用了 IntroSort(内省排序) 算法。这是快速排序、插入排序和堆排序的混合体,确保了在绝大多数情况下性能最优且不会栈溢出。
下面深入剖析 C# 内部是如何一步一步执行的:
1. 方法调用链(从外部到内部)
  • 第 1 层(List 层):List<T>.Sort(Comparison<T>) 接收你的 Lambda 表达式。
  • 第 2 层(包装层):List 内部会立刻将这个委托包装成一个 IComparer<T> 接口实例(具体是 Array.FunctorComparer<T>)。因为底层的数组排序只认接口,不认委托。
  • 第 3 层(核心层):调用 Array.Sort<T>(T[] array, IComparer<T> comparer) 进行真正的内存排序。

2. 核心算法:IntroSort(内省排序)
在 .NET 6+(以及 .NET Core)中,Array.Sort 内部实现是 IntroSort,它分三个阶段智能切换:
  • 快速排序(QuickSort):默认使用三路划分(Dual-Pivot Quicksort)进行递归。

    • 算法会递归地选取基准(Pivot),将小于基准的放左边,大于基准的放右边。

  • 堆排序(HeapSort):如果快速排序的递归深度超过 2 * log2(n),说明数据分布极差(比如正好倒序或大量重复),为了避免栈溢出或性能退化到 O(n²),算法强行切换成堆排序,保证最坏情况也是 O(n log n)。
  • 插入排序(InsertionSort):当划分后的子数组大小小于或等于 16 时,快速排序的递归停止,转为使用插入排序。因为小数组下插入排序的常数极小,比继续递归快得多。

3. 你的 Lambda 是如何被执行的?(比较器原理)
排序算法在内部需要判断两个元素 a 和 b 谁大谁小时,会调用你的委托。
  • 算法内部伪代码:int result = comparison(elementX, elementY);
  • 根据返回值决定顺序:
    • 返回值 < 0:将 elementX 排在 elementY 之前。
    • 返回值 > 0:将 elementY 排在 elementX 之前。
    • 返回值 == 0:保持原相对顺序(稳定)。


重点分析你的代码:(a,b) => b.Weight.CompareTo(a.Weight)
假设 a 的 Weight 是 5,b 的 Weight 是 10:
  • 代码执行 10.CompareTo(5),返回 1(正数)。
  • 正数意味着算法认为 a(原来的 5)应该排在 b(原来的 10)之后。
  • 因为大的排在了小的前面,所以结果是 降序(从大到小)。

4. 微小细节(对于值类型的优化)
由于 Weight 通常是一个值类型(比如 int,short),这里的 CompareTo 方法没有装箱开销。并且,List.Sort 的 Comparison<T> 重载在 .NET Core 3.0+ 中已被高度优化,相比实现 IComparer<T> 类,使用 Lambda 不会产生额外的接口虚调用开销,JIT 编译器(特别是 Tiered Compilation)有能力将其内联(Inline)掉,性能极佳。
5. 空间复杂度(是否占内存?)
  • 原地排序:该算法直接在 selfCardList 的内部数组上进行元素交换,不额外创建新 List 存储元素,内存占用极小(仅递归栈内存)。
  • 在你的例子中,它不会产生新的 List<Card> 实例。

6. 异常情况(当你遇到报错时)
  • 如果 selfCardList 是 null,会抛 ArgumentNullException。
  • 如果你的 Card.Weight 是 short 且可能为 null(可空类型 short?),而你没有判空,CompareTo 会抛出 NullReferenceException(因为短路的 null 对象无法调用方法)。


总结一句话:你的代码底层使用了 IntroSort 混合算法,时间复杂度在 O(n log n) 到 O(n) 之间,利用你提供的 Lambda 比较逻辑(通过返回正/负值)实现了对 Weight 的降序排列,整个过程不占用新内存且执行效率极高。

















您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|游戏黄埔游戏开发 ( 豫ICP备2024088136号-1|豫公网安备41040202000275号 )

GMT+8, 2026-6-30 20:00 , Processed in 0.043962 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表