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 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/smile_Ho/article/details/107978493
posted @ 2021-11-17 14:46  dreamw  阅读(739)  评论(0编辑  收藏  举报