.Net Framework 4.0 内部排序探索
简介
一时好奇心起,想一窥.Net Framework 4.0内部究竟是使用何种算法排序。以前听人说Framework内部是使用的快速排序,但究竟耳听为虚,眼见为实。主要通过JetBrains dotPeek 1.2作为工具反编译Framework的代码进行查看,也参考了其他很多资料。本人才疏学浅,其中难免存在错误,希望大家不吝指教。
数组
众所周知,数组实质上是Array类的实例。呃,要是被代表了,可以通过如下方式验证:
数组排序方法
初一看,数组的排序方法似乎很多,如下图:
但是只要我们再认真分析一下,可以发现可以根据是否为泛型,是否带关键字数组将排序方法分成4类,其余的全是重载方法。即:
public static void Sort<T>(T[] array);
public static void Sort(Array array);
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items);
public static void Sort(Array keys[], Array items);
重载方法包含的参数有:
- int index,从指定索引位置开始排序
- int length,从指定索引位置开始,需要排序的元素的个数
- ICompare<T> comparer,排序时进行比较的对象
- Comparison<T> comparison,排序时用于比较的委托
非泛型不带关键字数组排序方法
4种方法内部探究
这一系列共有4个方法:
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
public static void Sort(Array array)
{
if (array == null)
throw new ArgumentNullException("array");
Array.Sort(array, null, array.GetLowerBound(0), array.Length, null);
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static void Sort(Array array, int index, int length)
{
Array.Sort(array, null, index, length, null);
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
public static void Sort(Array array, IComparer comparer)
{
if (array == null)
throw new ArgumentNullException("array");
Array.Sort(array, null, array.GetLowerBound(0), array.Length, comparer);
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static void Sort(Array array, int index, int length, IComparer comparer)
{
Array.Sort(array, null, index, length, comparer);
}
比较这4个方法,发现其归根到底都调用了非泛型不带关键字数组排序方法:
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[SecuritySafeCritical]
public static void Sort(Array keys, Array items, int index, int length, IComparer comparer)
{
if (keys == null)
throw new ArgumentNullException("keys");
if (keys.Rank != 1 || items != null && items.Rank != 1)
throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
if (items != null && keys.GetLowerBound(0) != items.GetLowerBound(0))
throw new ArgumentException(Environment.GetResourceString("Arg_LowerBoundsMustMatch"));
if (index < keys.GetLowerBound(0) || length < 0)
throw new ArgumentOutOfRangeException(length < 0 ? "length" : "index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (keys.Length - (index - keys.GetLowerBound(0)) < length || items != null && index - items.GetLowerBound(0) > items.Length - length)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
if (length <= 1 || (comparer == Comparer.Default || comparer == null) && Array.TrySZSort(keys, items, index, index + length - 1))
return;
object[] keys1 = keys as object[];
object[] items1 = null;
if (keys1 != null)
items1 = items as object[];
if (keys1 != null && (items == null || items1 != null))
new Array.SorterObjectArray(keys1, items1, comparer).Sort(index, length);
else
new Array.SorterGenericArray(keys, items, comparer).Sort(index, length);
}
阅读代码,我们可以发现会首先尝试Array的TrySZSort方法,成功则直接返回。接着当关键字数组为object[]且项数组为空或项数组也为object[]时,将会调用SorterObjectArray的排序方法,否则调用SorterGenericArray的排序方法
TrySZSort方法
SZ的是single-dimension,zero-based的简称,即一维0基数组,又称为向量(vector)。其性能是最佳的,因为可以一些特殊的IL指令来处理。
TrySZSort的方法代码如下:
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail), SecurityCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool TrySZSort(Array keys, Array items, int left, int right);
可以发现该方法由CLR内部实现,但是好在现在CoreCLR已经开源了,我们可以通过CoreCLR大致了解到这个函数是做什么的。经过查找,发现在一个名叫ArrayHelper的类中发现该发现,代码如下:
FCIMPL4(FC_BOOL_RET, ArrayHelper::TrySZSort, ArrayBase * keys, ArrayBase * items, UINT32 left, UINT32 right)
FCALL_CONTRACT; VALIDATEOBJECT(keys);
VALIDATEOBJECT(items);
_ASSERTE(keys != NULL); // <TODO>@TODO: Eventually, consider adding support for single dimension arrays with
// non-zero lower bounds. VB might care. </TODO>
if (keys->GetRank() != 1 || keys->GetLowerBoundsPtr()[0] != 0)
FC_RETURN_BOOL(FALSE); _ASSERTE(left <= right);
_ASSERTE(right < keys->GetNumComponents() || keys->GetNumComponents() == 0); TypeHandle keysTH = keys->GetArrayElementTypeHandle();
const CorElementType keysElType = keysTH.GetVerifierCorElementType();
if (!CorTypeInfo::IsPrimitiveType_NoThrow(keysElType))
FC_RETURN_BOOL(FALSE);
if (items != NULL) {
TypeHandle itemsTH = items->GetArrayElementTypeHandle();
if (keysTH != itemsTH)
FC_RETURN_BOOL(FALSE); // Can't currently handle sorting different types of arrays.
} // Handle special case of a 0 element range to sort.
// Consider both Sort(array, x, x) and Sort(zeroLen, 0, zeroLen.Length-1);
if (left == right || right == 0xffffffff)
FC_RETURN_BOOL(TRUE); switch(keysElType) {
case ELEMENT_TYPE_I1:
ArrayHelpers<I1>::IntrospectiveSort((I1*) keys->GetDataPtr(), (I1*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break; case ELEMENT_TYPE_U1:
case ELEMENT_TYPE_BOOLEAN:
ArrayHelpers<U1>::IntrospectiveSort((U1*) keys->GetDataPtr(), (U1*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break; case ELEMENT_TYPE_I2:
ArrayHelpers<I2>::IntrospectiveSort((I2*) keys->GetDataPtr(), (I2*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break; case ELEMENT_TYPE_U2:
case ELEMENT_TYPE_CHAR:
ArrayHelpers<U2>::IntrospectiveSort((U2*) keys->GetDataPtr(), (U2*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break; case ELEMENT_TYPE_I4:
ArrayHelpers<I4>::IntrospectiveSort((I4*) keys->GetDataPtr(), (I4*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break; case ELEMENT_TYPE_U4:
ArrayHelpers<U4>::IntrospectiveSort((U4*) keys->GetDataPtr(), (U4*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break; case ELEMENT_TYPE_R4:
{
R4 * R4Keys = (R4*) keys->GetDataPtr();
R4 * R4Items = (R4*) (items == NULL ? NULL : items->GetDataPtr()); // Comparison to NaN is always false, so do a linear pass
// and swap all NaNs to the front of the array
left = ArrayHelpers<R4>::NaNPrepass(R4Keys, R4Items, left, right);
if(left != right) ArrayHelpers<R4>::IntrospectiveSort(R4Keys, R4Items, left, right);
break;
}; case ELEMENT_TYPE_I8:
ArrayHelpers<I8>::IntrospectiveSort((I8*) keys->GetDataPtr(), (I8*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break; case ELEMENT_TYPE_U8:
ArrayHelpers<U8>::IntrospectiveSort((U8*) keys->GetDataPtr(), (U8*) (items == NULL ? NULL : items->GetDataPtr()), left, right);
break; case ELEMENT_TYPE_R8:
{
R8 * R8Keys = (R8*) keys->GetDataPtr();
R8 * R8Items = (R8*) (items == NULL ? NULL : items->GetDataPtr()); // Comparison to NaN is always false, so do a linear pass
// and swap all NaNs to the front of the array
left = ArrayHelpers<R8>::NaNPrepass(R8Keys, R8Items, left, right);
if(left != right) ArrayHelpers<R8>::IntrospectiveSort(R8Keys, R8Items, left, right);
break;
}; case ELEMENT_TYPE_I:
case ELEMENT_TYPE_U:
// In V1.0, IntPtr & UIntPtr are not fully supported types. They do
// not implement IComparable, so searching & sorting for them should
// fail. In V1.1 or V2.0, this should change.
FC_RETURN_BOOL(FALSE); default:
_ASSERTE(!"Unrecognized primitive type in ArrayHelper::TrySZSort");
FC_RETURN_BOOL(FALSE);
}
FC_RETURN_BOOL(TRUE);
FCIMPLEND
大致可以看出,该方法的作用是对Framework的基本类型进行排序,排序也使用了内省排序。内省排序详见后面。
SorterObjectArray
我们来看一下SorterObjectArray的构造函数及Sort方法:
private object[] keys;
private object[] items;
private IComparer comparer;
internal SorterObjectArray(object[] keys, object[] items, IComparer comparer)
{
if (comparer == null)
{
comparer = Comparer.Default;
}
this.keys = keys;
this.items = items;
this.comparer = comparer;
}
构造函数很简单,仅仅赋值字段
internal void Sort(int left, int length)
{
if (BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
{
this.IntrospectiveSort(left, length);
return;
}
this.DepthLimitedQuickSort(left, length + left - 1, 32);
}
初看一下代码 ,发现关键语句是BinaryCompatibility.TargetsAtLeast_Desktop_V4_5,其决定了究竟使用了哪种排序方式。从字面意思上是说是否为桌面版本4.5及以上,经过验证后也确实如此,但因为与主题关系不大,就不细说,仅简单说下原理。
编译器在编译程序集时,会加上TargetFramework特性,.Network Framework通过检测该特性来确定框架版本,如下是4.0的一个程序集示例:
SorterObjectArray的DepthLimitedQuickSort
DepthLimitedQuickSort从字面意思来看,是深度限制快速排序,其代码如下:
private void DepthLimitedQuickSort(int left, int right, int depthLimit)
{
do
{
if (depthLimit == 0)
{
try
{
this.Heapsort(left, right);
break;
}
catch (IndexOutOfRangeException)
{
throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", new object[]
{
this.comparer
}));
}
catch (Exception innerException)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), innerException);
}
}
int num = left;
int num2 = right;
int median = Array.GetMedian(num, num2);
try
{
this.SwapIfGreaterWithItems(num, median);
this.SwapIfGreaterWithItems(num, num2);
this.SwapIfGreaterWithItems(median, num2);
}
catch (Exception innerException2)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), innerException2);
}
object obj = this.keys[median];
do
{
try
{
while (this.comparer.Compare(this.keys[num], obj) < 0)
{
num++;
}
while (this.comparer.Compare(obj, this.keys[num2]) < 0)
{
num2--;
}
}
catch (IndexOutOfRangeException)
{
throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", new object[]
{
this.comparer
}));
}
catch (Exception innerException3)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), innerException3);
}
if (num > num2)
{
break;
}
if (num < num2)
{
object obj2 = this.keys[num];
this.keys[num] = this.keys[num2];
this.keys[num2] = obj2;
if (this.items != null)
{
object obj3 = this.items[num];
this.items[num] = this.items[num2];
this.items[num2] = obj3;
}
}
num++;
num2--;
}
while (num <= num2);
depthLimit--;
if (num2 - left <= right - num)
{
if (left < num2)
{
this.DepthLimitedQuickSort(left, num2, depthLimit);
}
left = num;
}
else
{
if (num < right)
{
this.DepthLimitedQuickSort(num, right, depthLimit);
}
right = num2;
}
}
while (left < right);
}
调用时深度为32,每调用一次,深度减1,深度大于0时使用快速排序,当深度为0时即转入堆排序。在使用快速排序时,选取首、尾和首尾中间三个索引中取值为中间的对象作为主元。然后取左右两边较长的序列进入下一轮快速排序。
用到的其余代码如下:
internal void SwapIfGreaterWithItems(int a, int b)
{
if (a != b && this.comparer.Compare(this.keys[a], this.keys[b]) > 0)
{
object obj = this.keys[a];
this.keys[a] = this.keys[b];
this.keys[b] = obj;
if (this.items != null)
{
object obj2 = this.items[a];
this.items[a] = this.items[b];
this.items[b] = obj2;
}
}
}
private void Swap(int i, int j)
{
object obj = this.keys[i];
this.keys[i] = this.keys[j];
this.keys[j] = obj;
if (this.items != null)
{
object obj2 = this.items[i];
this.items[i] = this.items[j];
this.items[j] = obj2;
}
}
private void Heapsort(int lo, int hi)
{
int num = hi - lo + 1;
for (int i = num / 2; i >= 1; i--)
{
this.DownHeap(i, num, lo);
}
for (int j = num; j > 1; j--)
{
this.Swap(lo, lo + j - 1);
this.DownHeap(1, j - 1, lo);
}
}
private void DownHeap(int i, int n, int lo)
{
object obj = this.keys[lo + i - 1];
object obj2 = (this.items != null) ? this.items[lo + i - 1] : null;
while (i <= n / 2)
{
int num = 2 * i;
if (num < n && this.comparer.Compare(this.keys[lo + num - 1], this.keys[lo + num]) < 0)
{
num++;
}
if (this.comparer.Compare(obj, this.keys[lo + num - 1]) >= 0)
{
break;
}
this.keys[lo + i - 1] = this.keys[lo + num - 1];
if (this.items != null)
{
this.items[lo + i - 1] = this.items[lo + num - 1];
}
i = num;
}
this.keys[lo + i - 1] = obj;
if (this.items != null)
{
this.items[lo + i - 1] = obj2;
}
}
SorterObjectArray的IntrospectiveSort
IntrospectiveSort的代码如下:
private void IntrospectiveSort(int left, int length)
{
if (length < 2)
{
return;
}
try
{
this.IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2(this.keys.Length));
}
catch (IndexOutOfRangeException)
{
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(this.comparer);
}
catch (Exception innerException)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), innerException);
}
} private void IntroSort(int lo, int hi, int depthLimit)
{
while (hi > lo)
{
int num = hi - lo + 1;
if (num <= 16)
{
if (num == 1)
{
return;
}
if (num == 2)
{
this.SwapIfGreaterWithItems(lo, hi);
return;
}
if (num == 3)
{
this.SwapIfGreaterWithItems(lo, hi - 1);
this.SwapIfGreaterWithItems(lo, hi);
this.SwapIfGreaterWithItems(hi - 1, hi);
return;
}
this.InsertionSort(lo, hi);
return;
}
else
{
if (depthLimit == 0)
{
this.Heapsort(lo, hi);
return;
}
depthLimit--;
int num2 = this.PickPivotAndPartition(lo, hi);
this.IntroSort(num2 + 1, hi, depthLimit);
hi = num2 - 1;
}
}
}
private int PickPivotAndPartition(int lo, int hi)
{
int num = lo + (hi - lo) / 2;
this.SwapIfGreaterWithItems(lo, num);
this.SwapIfGreaterWithItems(lo, hi);
this.SwapIfGreaterWithItems(num, hi);
object obj = this.keys[num];
this.Swap(num, hi - 1);
int i = lo;
int num2 = hi - 1;
while (i < num2)
{
while (this.comparer.Compare(this.keys[++i], obj) < 0)
{
}
while (this.comparer.Compare(obj, this.keys[--num2]) < 0)
{
}
if (i >= num2)
{
break;
}
this.Swap(i, num2);
}
this.Swap(i, hi - 1);
return i;
}
在其中用到的FloorLog2代码如下:
internal static int FloorLog2(int n)
{
int num = 0;
while (n >= 1)
{
++num;
n /= 2;
}
return num;
}
其余用到的方法请参见上面的DepthLimitedQuickSort,初始深度为长度的2的对数取下界的2倍,其流程图如下:
SorterObjectArray排序的总结
可以看到,不论是DepthLimitedQuickSort还是IntrospectiveSort,都是内省排序的变种。内省排序是一种混合排序算法,以快速排序开始并在超过一定的递归深度后转换为堆排序。解决了快速排序在最坏情况下时间复杂度变为O(n2)的问题。随便说一句,在STL中也使用了内省排序。
至于递归深度的选择,在Framework 4.5以上,是,以下是32。这正是O(n log n) 。对于32来说,2的32方是4G,而CLR上运行的程序分配的内存不为超过2G。(不要问我是怎么知道的,我们的项目大约在超过1.2个G的时候崩溃过,当然在不同情况下最大可用内存不一样)
SorterGenericArray
SorterGenericArray与SorterObjectArray基本一样,只是将在SorterObjectArray的索引器替换Array的GetValue和SetValue。就不再细说了。
非泛型带关键字数组排序方法
从上面也可以看出,非泛型不带关键字数组排序方法本质上正是调用的非泛型带关键字数组排序的public static void Sort(Array array, int index, int length, IComparer comparer)方法,而非泛型带关键值数组的其余三个方法本质也同样是调用该方法,而该方法在前面已经分析过了,就不再说了。
泛型不带关键字数组排序方法
泛型不带关键字数组排序方法共5个,而最终调用的是public static void Sort<T>(T[] array, int index, int length, IComparer<T> comparer)这个方法。该方法如下:
[SecuritySafeCritical]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
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) && Array.TrySZSort((Array) array, (Array) null, index, index + length - 1))
return;
ArraySortHelper<T>.Default.Sort(array, index, length, comparer);
}
查看ArraySortHelper<T>代码,发现该类代码也与泛型不带关键字数组排序方法逻辑完全一致,就不再细说了。
泛型带关键字数组排序方法
泛型带关键字数组排序方法共4个,而最终调用的是public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length, IComparer<TKey> comparer)这个方法。该方法如下:
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[SecuritySafeCritical]
public static void Sort<TKey, TValue>(TKey[] keys, TValue[] items, int index, int length, IComparer<TKey> comparer)
{
if (keys == null)
throw new ArgumentNullException("keys");
if (index < 0 || length < 0)
throw new ArgumentOutOfRangeException(length < 0 ? "length" : "index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (keys.Length - index < length || items != null && index > items.Length - length)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
if (length <= 1 || (comparer == null || comparer == Comparer<TKey>.Default) && Array.TrySZSort((Array) keys, (Array) items, index, index + length - 1))
return;
if (items == null)
Array.Sort<TKey>(keys, index, length, comparer);
else
ArraySortHelper<TKey, TValue>.Default.Sort(keys, items, index, length, comparer);
}
该方法在items为空时直接调用泛型带关键字数组排序方法,在其他情况下调用ArraySortHelper<TKey, TValue>的排序方法。
查看ArraySortHelper<TKey, TValue>的代码,发现该类代码也与泛型带关键字数组排序方法逻辑完全一致,就不再细说了。
ArrayList
ArrayList这货虽然现在很少用了,但是毕竟了曾风光了一段时间,还是提一下,通过查看其代码,发现底层还是调用的Array的非泛型不带关键字数组的排序方法。这也不奇怪,跟List一样,底层用的都是数组。
public virtual void Sort(int index, int count, IComparer comparer)
{
if (index < 0)
{
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (this._size - index < count)
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
}
Array.Sort(this._items, index, count, comparer);
this._version++;
}
List
跟ArrayList类似,其底层调用的是Array的泛型不带关键字数组的排序方法。代码如下:
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 (this._size - index < count)
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
Array.Sort<T>(this._items, index, count, comparer);
++this._version;
}
[__DynamicallyInvokable]
public void Sort(Comparison<T> comparison)
{
if (comparison == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
if (this._size <= 0)
return;
Array.Sort<T>(this._items, 0, this._size, (IComparer<T>) new Array.FunctorComparer<T>(comparison));
}
Linq排序
OrderBy与OrderByDescending
通过查看代码,发现OrderBy与OrderByDescending基本一致,都使用了OrderedEnumerable<TSource, TKey>类,代码如下:
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
return (IOrderedEnumerable<TSource>) new OrderedEnumerable<TSource, TKey>(source, keySelector, (IComparer<TKey>) null, false);
} [__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{
return (IOrderedEnumerable<TSource>) new OrderedEnumerable<TSource, TKey>(source, keySelector, comparer, false);
} [__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
return (IOrderedEnumerable<TSource>) new OrderedEnumerable<TSource, TKey>(source, keySelector, (IComparer<TKey>) null, true);
} [__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{
return (IOrderedEnumerable<TSource>) new OrderedEnumerable<TSource, TKey>(source, keySelector, comparer, true);
}
而OrderedEnumerable<TSource, TKey>继承自OrderedEnumerable<TElement>,OrderedEnumerable<TSource, TKey>中排序使用了EnumerableSorter<TElement, TKey>,而EnumerableSorter<TElement, TKey>继承自EnumerableSorter<TElement>。在EnumerableSorter<TElement>我们可以发现排序的关键代码:
internal int[] Sort(TElement[] elements, int count)
{
this.ComputeKeys(elements, count);
int[] map = new int[count];
for (int index = 0; index < count; ++index)
map[index] = index;
this.QuickSort(map, 0, count - 1);
return map;
} private void QuickSort(int[] map, int left, int right)
{
do
{
int left1 = left;
int right1 = right;
int index1 = map[left1 + (right1 - left1 >> 1)];
while (true)
{
do
{
if (left1 >= map.Length || this.CompareKeys(index1, map[left1]) <= 0)
{
while (right1 >= 0 && this.CompareKeys(index1, map[right1]) < 0)
--right1;
if (left1 <= right1)
{
if (left1 < right1)
{
int num = map[left1];
map[left1] = map[right1];
map[right1] = num;
}
++left1;
--right1;
}
else
break;
}
else
goto label_1;
}
while (left1 <= right1);
break;
label_1:
++left1;
}
if (right1 - left <= right - left1)
{
if (left < right1)
this.QuickSort(map, left, right1);
left = left1;
}
else
{
if (left1 < right)
this.QuickSort(map, left1, right);
right = right1;
}
}
while (left < right);
}
原来是快速排序。
ThenBy和ThenByDescending
查看代码,发现ThenBy和ThenByDescending基本一致,都是传入IOrderedEnumerable<TSource>,返回其CreateOrderedEnumerable方法调用。
[__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{ if (source == null) throw Error.ArgumentNull("source"); else
return source.CreateOrderedEnumerable<TKey>(keySelector, (IComparer<TKey>) null, false);
} [__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{ if (source == null) throw Error.ArgumentNull("source"); else
return source.CreateOrderedEnumerable<TKey>(keySelector, comparer, false);
} [__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{ if (source == null) throw Error.ArgumentNull("source"); else
return source.CreateOrderedEnumerable<TKey>(keySelector, (IComparer<TKey>) null, true);
} [__DynamicallyInvokable]
public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{ if (source == null) throw Error.ArgumentNull("source"); else
return source.CreateOrderedEnumerable<TKey>(keySelector, comparer, true);
}
而在上面,我们已经发现了OrderBy与OrderByDescending都返回了OrderedEnumerable<TSource, TKey>,在其中找到CreateOrderedEnumerable方法。
IOrderedEnumerable<TElement> IOrderedEnumerable<TElement>.CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
OrderedEnumerable<TElement, TKey> orderedEnumerable = new OrderedEnumerable<TElement, TKey>(this.source, keySelector, comparer, descending);
orderedEnumerable.parent = this;
return (IOrderedEnumerable<TElement>) orderedEnumerable;
}
这说明正是在前面排序的基础上进行再次排序。
参考资料
C#集合--数组 - On the road.... - 博客园
Introsort - Wikipedia, the free encyclopedia:
一并予以感谢
.Net Framework 4.0 内部排序探索的更多相关文章
- 七种机器内部排序的原理与C语言实现,并计算它们的比较次数与移动次数。
内部排序是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列. 排序是计算机程序设计中的一种重要操作,其功能是对一个数据元素集合或序列重新排列成一个按数据元素某个相知有序的序列.排序分为 ...
- 七内部排序算法汇总(插入排序、Shell排序、冒泡排序、请选择类别、、高速分拣合并排序、堆排序)
写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的随意序列,又一次排列成一个按keyword有序的序列.因此排序掌握各种排序算法很重要. 对以下介绍的各个排序,我们假定全部排 ...
- C++ 内部排序(一)
先讲两个概念,所谓内部排序,指待排序的节点均存储在内存中.所谓排序的稳定性,指排序后,值相等的两个元素原来相对的位置是否发生变化了.举个例子. 待排序列:3(1),1,5,3(2) 稳定排序:1,3 ...
- Spring Framework 5.0 新特性
Spring Framework 5.0是在Spring Framework 4.0之后将近四年内一次重大的升级. 在这个时间框架内,主要的发展之一就是Spring Boot项目的演变. Spring ...
- 浅析Entity Framework Core2.0的日志记录与动态查询条件
前言 Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章.. 本文主要是浅析一下Entity Framework Core2.0的日志记录与动态查询条件 去 ...
- entity framework 实现按照距离排序
在做项目时,经常会遇到“离我最近”这种需求.顾名思义,它需要根据用户的经纬度和事物的经纬度计算距离,然后进行排序,最后分页(当然这些操作要在数据库中进行,否则就变成假分页了). 我们通常可以用sql语 ...
- 排序算法练习--JAVA(:内部排序:插入、选择、冒泡、快速排序)
排序算法是数据结构中的经典算法知识点,也是笔试面试中经常考察的问题,平常学的不扎实笔试时候容易出洋相,回来恶补,尤其是碰到递归很可能被问到怎么用非递归实现... 内部排序: 插入排序:直接插入排序 选 ...
- 内部排序->基数排序->链式基数排序
文字描述 基数排序是和前面各类排序方法完全不相同,前面几篇文章介绍的排序算法的实现主要是通过关键字间的比较和移动记录这两种操作,而实现基数排序不需要进行记录关键字间的比较.基数排序是一种借助多关键字排 ...
- 内部排序比较(Java版)
内部排序比较(Java版) 2017-06-21 目录 1 三种基本排序算法1.1 插入排序1.2 交换排序(冒泡)1.3 选择排序(简单)2 比较3 补充3.1 快速排序3.2 什么是桶排序3.3 ...
随机推荐
- 【iOS】Quartz2D矩阵操作
前面画基本图形时,画四边形是由几条直线拼接成的,现在有更简便的方法. 一.关于矩阵操作 1.画一个四边形 通过设置两个端点(长和宽)来完成一个四边形的绘制. 代码: - (void)drawRect: ...
- Android开发中的问题及相应解决(持续更新)
最近博客写的少了,以后还得经常更新才行. ------------------------------------------------------------ 1.特定业务需求下try cath ...
- Virtual DOM 算法
前端 virtual-dom react.js javascript 目录: 1 前言 2 对前端应用状态管理思考 3 Virtual DOM 算法 4 算法实现 4.1 步骤一:用JS对象模拟DOM ...
- MySQL到MsSQL的迁移工具——SSMA
SQL Server迁移助手(SSMA)团队开发了针对MySQL的迁移助手Microsoft SQL Server Migration Assistant 2008 for MySQL.微软同时发布了 ...
- Apache服务器的URL重定向
前端时间要整个Apache重定向功能,在此记录一下. 一.安装Apache Windows版本官方下载安装文件httpd-2.2.21-win32-x86-openssl-0.9.8r,选择安装目录, ...
- 转:使用vs2013打开VS2015的工程文件的解决方案(适用于大多数vs低版本打开高版本)
http://www.cnblogs.com/WayneLiu/p/5060277.html 前言:重装系统前我使用的是vs2015(有点装*),由于使用2015实在在班上太另类了, 导致我想在其他同 ...
- iOS第三方类库JSPatch(热更新)
---------------------------------------------------------------------------------------------------- ...
- 【原】IOS中KVO模式的解析与应用
最近老翁在项目中多处用到了KVO,深感这种模式的好处.现总结如下: 一.概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知.简单 ...
- 【原】自定义UIPageControl的圆点
在下面的两种情况下会导致圆点贴图刷新: 1.用户调用setCurrentPage:(NSInteger)currentPage时 所以重载这个函数便可拦截 2.点击圆点矩形区域时 这说明,我们 ...
- Android线程池(一)
本篇文章主要介绍Android自带的线程池的使用. 首先要引入线程池的概念 线程池:是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务. 线程池线程都是后台线程.每个线 ...