.NET源代码的内部排序实现
使用JetBrains的DotPeek工具能够方便地查看.net的部分源代码。于是看了一下.NET的内部是怎样实现排序的算法。
在System.Collections.Generic 命名空间下能够看到ArraySortHelper<T>的实现。
- public void Sort(T[] keys, int index, int length, IComparer<T> comparer)
- {
- try
- {
- if (comparer == null)
- comparer = (IComparer<T>) Comparer<T>.Default;
- if (BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
- ArraySortHelper<T>.IntrospectiveSort(keys, index, length, comparer);
- else
- ArraySortHelper<T>.DepthLimitedQuickSort(keys, index, length + index - 1, comparer, 32);
- }
- catch (IndexOutOfRangeException ex)
- {
- IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer((object) comparer);
- }
- catch (Exception ex)
- {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), ex);
- }
- }
发如今.NET4.5以上的版本号,開始使用一种叫做 Introspective Sort的排序方法。
- internal static void IntrospectiveSort(T[] keys, int left, int length, IComparer<T> comparer)
- {
- if (length < 2)
- return;
- ArraySortHelper<T>.IntroSort(keys, left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2(keys.Length), comparer);
- }
- private static void IntroSort(T[] keys, int lo, int hi, int depthLimit, IComparer<T> comparer)
- {
- for (; hi > lo; {
- int num;
- hi = num - 1;
- }
- )
- {
- int num = hi - lo + 1;
- if (num <= 16)
- {
- if (num == 1)
- break;
- if (num == 2)
- {
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, lo, hi);
- break;
- }
- else if (num == 3)
- {
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, lo, hi - 1);
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, lo, hi);
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, hi - 1, hi);
- break;
- }
- else
- {
- ArraySortHelper<T>.InsertionSort(keys, lo, hi, comparer);
- break;
- }
- }
- else if (depthLimit == 0)
- {
- ArraySortHelper<T>.Heapsort(keys, lo, hi, comparer);
- break;
- }
- else
- {
- --depthLimit;
- num = ArraySortHelper<T>.PickPivotAndPartition(keys, lo, hi, comparer);
- ArraySortHelper<T>.IntroSort(keys, num + 1, hi, depthLimit, comparer);
- }
- }
- }
- private static int PickPivotAndPartition(T[] keys, int lo, int hi, IComparer<T> comparer)
- {
- int index = lo + (hi - lo) / 2;
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, lo, index);
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, lo, hi);
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, index, hi);
- T obj = keys[index];
- ArraySortHelper<T>.Swap(keys, index, hi - 1);
- int i = lo;
- int j = hi - 1;
- while (i < j)
- {
- do
- ;
- while (comparer.Compare(keys[++i], obj) < 0);
- do
- ;
- while (comparer.Compare(obj, keys[--j]) < 0);
- if (i < j)
- ArraySortHelper<T>.Swap(keys, i, j);
- else
- break;
- }
- ArraySortHelper<T>.Swap(keys, i, hi - 1);
- return i;
- }
而.NET4.5下面使用的是还有一种排序的方案。
在排序的数字小于16个的时候,直接使用插入排序。
- private static void InsertionSort(T[] keys, int lo, int hi, IComparer<T> comparer)
- {
- for (int index1 = lo; index1 < hi; ++index1)
- {
- int index2 = index1;
- T x;
- for (x = keys[index1 + 1]; index2 >= lo && comparer.Compare(x, keys[index2]) < 0; --index2)
- keys[index2 + 1] = keys[index2];
- keys[index2 + 1] = x;
- }
- }
而假设大于16个的时候,且当递归深度在32次之内的话(也就是数字小于4GB的数量时),使用高速排序。
- internal static void DepthLimitedQuickSort(T[] keys, int left, int right, IComparer<T> comparer, int depthLimit)
- {
- while (depthLimit != 0)
- {
- int index1 = left;
- int index2 = right;
- int index3 = index1 + (index2 - index1 >> 1);
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, index1, index3);
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, index1, index2);
- ArraySortHelper<T>.SwapIfGreater(keys, comparer, index3, index2);
- T obj1 = keys[index3];
- do
- {
- while (comparer.Compare(keys[index1], obj1) < 0)
- ++index1;
- while (comparer.Compare(obj1, keys[index2]) < 0)
- --index2;
- if (index1 <= index2)
- {
- if (index1 < index2)
- {
- T obj2 = keys[index1];
- keys[index1] = keys[index2];
- keys[index2] = obj2;
- }
- ++index1;
- --index2;
- }
- else
- break;
- }
- while (index1 <= index2);
- --depthLimit;
- if (index2 - left <= right - index1)
- {
- if (left < index2)
- ArraySortHelper<T>.DepthLimitedQuickSort(keys, left, index2, comparer, depthLimit);
- left = index1;
- }
- else
- {
- if (index1 < right)
- ArraySortHelper<T>.DepthLimitedQuickSort(keys, index1, right, comparer, depthLimit);
- right = index2;
- }
- if (left >= right)
- return;
- }
- ArraySortHelper<T>.Heapsort(keys, left, right, comparer);
- }
而假设大于4GB的数量时,使用堆排序。
- private static void Heapsort(T[] keys, int lo, int hi, IComparer<T> comparer)
- {
- int n = hi - lo + 1;
- for (int i = n / 2; i >= 1; --i)
- ArraySortHelper<T>.DownHeap(keys, i, n, lo, comparer);
- for (int index = n; index > 1; --index)
- {
- ArraySortHelper<T>.Swap(keys, lo, lo + index - 1);
- ArraySortHelper<T>.DownHeap(keys, 1, index - 1, lo, comparer);
- }
- }
- private static void DownHeap(T[] keys, int i, int n, int lo, IComparer<T> comparer)
- {
- T x = keys[lo + i - 1];
- for (; i <= n / 2; {
- int num;
- i = num;
- }
- )
- {
- num = 2 * i;
- if (num < n && comparer.Compare(keys[lo + num - 1], keys[lo + num]) < 0)
- ++num;
- if (comparer.Compare(x, keys[lo + num - 1]) < 0)
- keys[lo + i - 1] = keys[lo + num - 1];
- else
- break;
- }
- keys[lo + i - 1] = x;
- }
最后,附上swap函数的实现:
- private static void SwapIfGreater(T[] keys, IComparer<T> comparer, int a, int b)
- {
- if (a == b || comparer.Compare(keys[a], keys[b]) <= 0)
- return;
- T obj = keys[a];
- keys[a] = keys[b];
- keys[b] = obj;
- }
- private static void Swap(T[] a, int i, int j)
- {
- if (i == j)
- return;
- T obj = a[i];
- a[i] = a[j];
- a[j] = obj;
- }
.NET源代码的内部排序实现的更多相关文章
- 七种机器内部排序的原理与C语言实现,并计算它们的比较次数与移动次数。
内部排序是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列. 排序是计算机程序设计中的一种重要操作,其功能是对一个数据元素集合或序列重新排列成一个按数据元素某个相知有序的序列.排序分为 ...
- 七内部排序算法汇总(插入排序、Shell排序、冒泡排序、请选择类别、、高速分拣合并排序、堆排序)
写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的随意序列,又一次排列成一个按keyword有序的序列.因此排序掌握各种排序算法很重要. 对以下介绍的各个排序,我们假定全部排 ...
- C++ 内部排序(一)
先讲两个概念,所谓内部排序,指待排序的节点均存储在内存中.所谓排序的稳定性,指排序后,值相等的两个元素原来相对的位置是否发生变化了.举个例子. 待排序列:3(1),1,5,3(2) 稳定排序:1,3 ...
- 排序算法练习--JAVA(:内部排序:插入、选择、冒泡、快速排序)
排序算法是数据结构中的经典算法知识点,也是笔试面试中经常考察的问题,平常学的不扎实笔试时候容易出洋相,回来恶补,尤其是碰到递归很可能被问到怎么用非递归实现... 内部排序: 插入排序:直接插入排序 选 ...
- 内部排序->其它->地址排序(地址重排算法)
文字描述 当每个记录所占空间较多,即每个记录存放的除关键字外的附加信息太大时,移动记录的时间耗费太大.此时,就可以像表插入排序.链式基数排序,以修改指针代替移动记录.但是有的排序方法,如快速排序和堆排 ...
- 内部排序->基数排序->链式基数排序
文字描述 基数排序是和前面各类排序方法完全不相同,前面几篇文章介绍的排序算法的实现主要是通过关键字间的比较和移动记录这两种操作,而实现基数排序不需要进行记录关键字间的比较.基数排序是一种借助多关键字排 ...
- 内部排序->归并排序->2-路归并排序
文字描述 假设初始序列有n个记录,则可看成是n个有序的字序列,每个字序列的长度为1,然后两两归并,得到[n/2]个长度为2或1的有序子序列:再两两归并,…, 如此重复,直到得到一个长度为n的有序序列为 ...
- 内部排序比较(Java版)
内部排序比较(Java版) 2017-06-21 目录 1 三种基本排序算法1.1 插入排序1.2 交换排序(冒泡)1.3 选择排序(简单)2 比较3 补充3.1 快速排序3.2 什么是桶排序3.3 ...
- Java实现各种内部排序算法
数据结构中常见的内部排序算法: 插入排序:直接插入排序.折半插入排序.希尔排序 交换排序:冒泡排序.快速排序 选择排序:简单选择排序.堆排序 归并排序.基数排序.计数排序 直接插入排序: 思想:每次将 ...
随机推荐
- Linux删除以破折号开头的文件Windows在批处理文件来删除隐藏属性
昨天去打印店打印的材料.结果中毒.所有的文件被隐藏.生成一个一堆快捷键.回来后.我很容易地把它放入Linux机,我想删除这些文件怪. 下面是该过程,遇到的问题. 1.您无法删除'-'该文件的开头 最初 ...
- 无法使用SQL login去登陆SQL Server - 'Password did not match'
原文:无法使用SQL login去登陆SQL Server - 'Password did not match' 出自:http://blogs.msdn.com/b/apgcdsd/archive/ ...
- POJ 3237 Tree (树链拆分)
主题链接~~> 做题情绪:了. 解题思路: 主要注意如何区间更新就ok了 . 树链剖分就是树上的线段树. 代码: #include<iostream> #include<sst ...
- c++读取文本文件
#include<iostream> #include<fstream> using namespace std; int main() { int a,b=-100000,c ...
- HDU 4283 You are the one(间隔DP)
标题效果: The TV shows such as You Are the One has been very popular. In order to meet the need of boys ...
- 深入Java虚拟机——类型装载、连接(转)
来自http://hi.baidu.com/holder/item/c38abf02de14c7d31ff046e0 Java虚拟机通过装载.连接和初始化一个Java类型,使该类型可以被正在运行的Ja ...
- HDU 1198 Farm Irrigation (并检查集合 和 dfs两种实现)
Farm Irrigation Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- 彩色图像上执行Mean Shift迭代搜索目标 ,维加权直方图 + 巴氏系数 + Mean Shift迭代
今天要给大家分享的是: 在彩色图像上进行Mean Shift迭代搜索目标 二维加权直方图+巴氏系数+Mean Shift迭代 关于 加权直方图.巴氏系数.Mean Shift迭代 这三者之间的关系请大 ...
- 采用xshell链路本地虚拟机Linux
昨天想安装在自己的机器看Linux.而使用xshell通路.但是这花了很长的时间,于xshell结束所有的提示"Could not connect to '192.168.54.100' ( ...
- 网络编程easy错误点-手知道
通常的网络编程socket编程.实际上.socket编程并不仅仅是满足网络间不同主机之间的通信,它也能实现同一台主机上不同进程间的通信需求. 其体如今创建socket时的參数的不同: int sock ...