C# List<>.Sort() 排序的底层实现原理_少侠Smile丶-程序员秘密
首先,C# List<>.Sort() 排序的底层实现原理就是快速排序 + 堆排序(.net 4.5用的内省排序)。
大佬可以 return了。
接下来,让我们一一还原案发现场。
源码干货预警,头大!!!!!
// 1,看到我们调用的Sort方法
public void Sort(IComparer<T> comparer)
{
Sort(0, Count, comparer);
}
// 2,进入Sort(), 这里只关注倒数第二行,调用了Array.Sort()
public void Sort(int index, int count, IComparer<T> comparer)
{
if (index < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
if (count < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
if (_size - index < count)
{
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
}
Array.Sort(_items, index, count, comparer);
_version++;
}
// 3, 这里只关注最后一行,调用了ArraySortHelper<T>.Default.Sort()
public static void Sort<T>(T[] array, int index, int length, IComparer<T> comparer)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (index < 0 || length < 0)
{
throw new ArgumentOutOfRangeException((length < 0) ? "length" : "index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (array.Length - index < length)
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
}
if (length > 1 && ((comparer != null && comparer != Comparer<T>.Default) || !TrySZSort(array, null, index, index + length - 1)))
{
ArraySortHelper<T>.Default.Sort(array, index, length, comparer);
}
}
// 4, 这一段,根据版本使用不同的排序
public void Sort(T[] keys, int index, int length, IComparer<T> comparer)
{
try
{
if (comparer == null)
{
comparer = Comparer<T>.Default;
}
// 如果.net版本是4.5 则执行IntrospectiveSort
if (BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
{
IntrospectiveSort(keys, index, length, comparer);
}
// 否则都执行深度限制快速排序, 深度限制是32
else
{
DepthLimitedQuickSort(keys, index, length + index - 1, comparer, 32);
}
}
catch (IndexOutOfRangeException)
{
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
}
catch (Exception innerException)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), innerException);
}
}
// 5,IntrospectiveSort 使用内省排序 , 不在本篇文章介绍中
internal static void IntrospectiveSort(T[] keys, int left, int length, IComparer<T> comparer)
{
if (length >= 2)
{
IntroSort(keys, left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2(keys.Length), comparer);
}
}
// 6,DepthLimitedQuickSort 重点!!!!!
// 深度限制 32 也就是说快排的轮次最大进行32轮, 32轮能排2^32个数
// 以下快排用的双边循环法 不清楚的可以参考我的博文 排序算法--快速排序的两种遍历方法(C#)
internal static void DepthLimitedQuickSort(T[] keys, int left, int right, IComparer<T> comparer, int depthLimit)
{
while (depthLimit != 0)
{
// 确定起始点,中点,终点
int num = left;
int num2 = right;
int num3 = num + (num2 - num >> 1);
// 将三个位置的顺序确定
SwapIfGreater(keys, comparer, num, num3);
SwapIfGreater(keys, comparer, num, num2);
SwapIfGreater(keys, comparer, num3, num2);
T val = keys[num3];
//找基准位置
while (true)
{
// 找到左边需要换位置的索引
if (comparer.Compare(keys[num], val) < 0)
{
num++;
continue;
}
// 找到右边需要换位置的索引
while (comparer.Compare(val, keys[num2]) < 0)
{
num2--;
}
// 如果超了 break
if (num > num2)
{
break;
}
// 否则交换
if (num < num2)
{
T val2 = keys[num];
keys[num] = keys[num2];
keys[num2] = val2;
}
// 两边都往中间缩一个
num++;
num2--;
// 判断是否超了
if (num > num2)
{
break;
}
}
depthLimit--;
if (num2 - left <= right - num)
{
if (left < num2)
{
// 排左边
DepthLimitedQuickSort(keys, left, num2, comparer, depthLimit);
}
left = num;
}
else
{
if (num < right)
{
// 排右边
DepthLimitedQuickSort(keys, num, right, comparer, depthLimit);
}
right = num2;
}
if (left >= right)
{
return;
}
}
// hello ,这里抓到一枚堆排同志
Heapsort(keys, left, right, comparer);
}
// 7, 接下来是堆排
private static void Heapsort(T[] keys, int lo, int hi, IComparer<T> comparer)
{
int num = hi - lo + 1;
// 构建堆
for (int num2 = num / 2; num2 >= 1; num2--)
{
DownHeap(keys, num2, num, lo, comparer);
}
// 交换堆顶与末尾元素,并重新构建堆
for (int num3 = num; num3 > 1; num3--)
{
Swap(keys, lo, lo + num3 - 1);
DownHeap(keys, 1, num3 - 1, lo, comparer);
}
}
// 8,堆下沉
private static void DownHeap(T[] keys, int i, int n, int lo, IComparer<T> comparer)
{
T val = keys[lo + i - 1];
while (i <= n / 2)
{
int num = 2 * i;
if (num < n && comparer.Compare(keys[lo + num - 1], keys[lo + num]) < 0)
{
num++;
}
if (comparer.Compare(val, keys[lo + num - 1]) >= 0)
{
break;
}
keys[lo + i - 1] = keys[lo + num - 1];
i = num;
}
keys[lo + i - 1] = val;
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)