.NET 4.5 这个版本的Array.Sort更改了STL的内观排序算法,那相对于快速排序内观排序到底有什么优化过的呢?

根据维基百科所说,这个排序算法首先从快速排序开始,当递归深度超过一定深度(深度为排序元素数量的对数值)后转为堆排序。

采用这个方法,Introsort既能在常规数据集上实现快速排序的高性能,又能在最坏情况下仍保持 O(N log N) 的时间复杂度。

由于这两种算法都属于比较排序算法,所以Introsort也是一个比较排序算法。

按我的理解可以说是快速排序+插入排序+堆排序的混合方式;

优化过的快速排序:

private static void IntroSort<T>(T[] array, int low, int height,
int depthLimit, IComparer<T> comparer, bool desc = false) {
while (height > low) {
int partitionSize = height - low + ; //判断区间长度少于等于16时候不再使用快速排序提升效率
if (partitionSize <= IntrosortSizeThreshold) {
if (partitionSize == ) {
return;
}
if (partitionSize == ) {
//长度为2的时候直接左右尝试交换
if (desc) {
SwapIfLessthan(array, low, height, comparer);
} else {
SwapIfGreater(array, low, height, comparer);
}
return;
}
if (partitionSize == ) {
//长度为3时候,三数取中分割法
if (desc) {
SwapMed3ByLessthan(array, low, height, height - , comparer);
} else {
SwapMed3(array, low, height, height - , comparer);
}
return;
} //使用插入排序算法
InsertionSort(array, low, height, desc);
return;
}
if (depthLimit == ) {
HeapSort(array, low, height, desc);
return;
}
depthLimit--;
//pivotpos划分后的基准记录的位置
//对R[low..high]做划分
int pivotpos = PickPivotAndPartition(array, low, height, comparer, desc);
//对右区间递归排序
IntroSort(array, pivotpos + , height, depthLimit, comparer, desc);
//对左区间递归排序 因为有个while所以不需要递归,相当于QuickSort(array,low,pivotpos-1);
height = pivotpos - ;
}
}

1.利用基于三中值分区的中枢值来做快排

        //分治法:三数取中分割法
private static int PickPivotAndPartition<T>(T[] keys, int lo, int hi,
IComparer<T> comparer, bool desc) {
//用区间中位记录作为基准
int median = GetMedian(lo, hi); //采取keys[lo],keys[median],keys[hi]三者之中的那个第二大的元素为主元时
//便能尽最大限度保证快速排序算法不会出现O(N^2)的最坏情况
if (desc) {
SwapMed3ByLessthan(keys, lo, hi, median, comparer);
} else {
SwapMed3(keys, lo, hi, median, comparer);
} //基准
T pivot = keys[median]; //注意:hi-1是因为上面的三数取中算法已经做了低位和高位比较,
//所以这里获取hi-1(前一个比较),下面的高位实际是高位前一个位置 //尝试中间和高位交换
Swap(keys, median, hi - ); int left = lo;
//这里意义是为了下面--right使用,
//如果数组是5开始递减应该是3开始,
//因为Swap(keys, median, hi - 1);
//已经做了比较减少一位
int right = hi - ; //从区间两端交替向中间扫描,直至left=right为止
while (left < right) {
if (desc) {
//left左边的元素大于pivot,right右边的元素都小于pivot
//线性时间的原地划分,只扫描数组一次就能完成 //使用++left为了跳过第一位,因为上面已经坐了三数取中
//从左向右扫描实,左边的元素比基准大,遇到小于pivot时候停止
while (comparer.Compare(keys[++left], pivot) > ) ; //从右向左扫描,右边的元素比基准小,遇到大于pivot时候停止
while (comparer.Compare(keys[--right], pivot) < ) ;
} else {
//left左边的元素小于pivot,right右边的元素都大于pivot
//线性时间的原地划分,只扫描数组一次就能完成 //使用++left为了跳过第一位,因为上面已经坐了三数取中
//从左向右扫描实,左边的元素比基准小,遇到大于pivot时候停止
while (comparer.Compare(keys[++left], pivot) < ) ; //从右向左扫描,右边的元素比基准大,遇到小于pivot时候停止
while (comparer.Compare(keys[--right], pivot) > ) ;
} //左右碰撞退出扫描,准备下次递归
if (left >= right) break; //进行交换
Swap(keys, left, right);
} //pivot 上面做了Swap(keys, median, hi - 1);
//中位和高位比较,所以这里需要基准位置left和高位(hi - 1 同上)交换,
//因为上面循环的--right已经跳过比较。
Swap(keys, left, hi - ); //基准记录已被最后定位
return left;
}

2.设定一个使用切分时数组长度的最小值,如果小于这个值,就使用插入排序(这个最小值根据经验给定,一般设定为16)

//判断区间长度少于等于16时候不再使用快读排序提升效率
if (partitionSize <= IntrosortSizeThreshold) {
if (partitionSize == ) {
return;
}
if (partitionSize == ) {
//长度为2的时候直接左右尝试交换
if (desc) {
SwapIfLessthan(array, low, height, comparer);
} else {
SwapIfGreater(array, low, height, comparer);
}
return;
}
if (partitionSize == ) {
//长度为3时候,三数取中分割法
if (desc) {
SwapMed3ByLessthan(array, low, height, height - , comparer);
} else {
SwapMed3(array, low, height, height - , comparer);
}
return;
} //使用插入排序算法
InsertionSort(array, low, height, desc);
return;
}

3.监视快排的递归深度,以确保高效的处理。如果快排递归深度超过log(n)级,那么内观排序切换到堆排序

 if (depthLimit == ) {
HeapSort(array, low, height, desc);
return;
}
depthLimit--;

源代码下载

Introsort(内观排序)的更多相关文章

  1. PAT 甲级 1053 Path of Equal Weight (30 分)(dfs,vector内元素排序,有一小坑点)

    1053 Path of Equal Weight (30 分)   Given a non-empty tree with root R, and with weight W​i​​ assigne ...

  2. Flex Array内置排序方法的使用

    在Array类中,提供内置的排序方法.排序是在软件开发的过程中,经常遇到的问题.通过这些内置的方法,可以快速轻便的进行排序操作. Array类提供sort方法对Array实例进行排序.sort方法没有 ...

  3. pandas技巧两则——列内元素统计和列内元素排序

    更新:后来忽然发现有个cumcount()函数,支持正排倒排,所以以下说的那些基本都没啥用了. 最近做比赛线上无甚进展,所以先小小地总结遇到的一些困难和解决的方法,以防之后忘记.毕竟总是忙着大步赶路的 ...

  4. PHP算法之排序算法(PHP内置排序函数)

    首先用实例来讲述一下PHP内置的一些排序函数 [a / k] sort [/ rsort]:[保留索引关系 / 按键名(保留键名关系,适用于关联数组)] 对数组进行排序,结束时数组单元将被从最低到最高 ...

  5. ABAP 动态内标排序

     动态内表怎样排序动态内表怎样排序 动态内表要排序时,因为不知道内表中的字段名字,所以不能直接用SORT table BY field1 field2... 可以使用下面的方法来实现:SORT tab ...

  6. 用redis实现动态时间段内统计排序

    问题描述 需要根据某类数据在动态时间段内的统计值对这些数据进行排名.例如按过去24小时内点赞数排名的帖子,每隔一小时计算一次结果.以下描述均针对这个例子展开. 解决思路 针对这种问题,我的第一反应是直 ...

  7. python 根据字符串内数字排序

    当我们使用python给一个由字符串组成的列表排序时,常常会排成这样 [‘10a’, ‘11b’, ‘1c’, ‘20d’, ‘21e’, ‘2f’] 这样的形式 ,然而我们想要 [ ‘1c’,‘2f ...

  8. JavaScript内置排序方法sort实现排序操作

    var arr = [10,8,6,9,1,7,2,13,5,1,9]; //sort排序 arr.sort(function(a,b){ //可以改变数组本身的排序方法 return a-b; }) ...

  9. Oracle-left join两表关联只取B表匹配到的第一条记录【over partition by(分组后对组内数据排序)】

    背景:  A表.B表两表关联,关联出来的结果里B表有不止一条,需求是只要B表结果中的某一条(按某字段排序) 经过百度,发现 row_number() over(partition by a order ...

随机推荐

  1. React.js再探(二)

    上文中说到了组件了. 我们使用组件的目的最大莫过于复用,提供生产效率. 那么,这时候组件就应该能够提供一些”api”出来,让开发者去定义在不同场景下的不同表现,比如,行为或外观等. 而这些“api”就 ...

  2. Android网络通信android-async-http入门

    android-async-http入门 门免费链接分享前:http://pan.baidu.com/s/1mg9SvgO 密码:cgg7 API原文:http://loopj.com/android ...

  3. java_ log4j的基本配置参数

    目标:  err级别发送邮件 ,要求美观 ,信息详细 开工: 材料: 三个jar ,版本不建议高,不能低. 方便起见,打包下载即可    http://pan.baidu.com/s/1mgmfyvY ...

  4. SQL 把表中字段存储的逗号隔开内容转换成列表形式

    原文:[原创]SQL 把表中字段存储的逗号隔开内容转换成列表形式 我们日常开发中,不管是表设计问题抑或是其他什么原因,或多或少都会遇到一张表中有一个字段存储的内容是用逗号隔开的列表. 具体效果如下图: ...

  5. Java初始阶段

    初时接触感觉Java与C语言有很多异曲同工之处. Java起源: Java之父:James Gosling 正式发布时间:1995年5月23日 其特点为:简单.面向对象.可移植.多线程.动态 其编译后 ...

  6. 客户端程序通过TCP通信传送"小文件"到服务器

    客户端程序通过TCP通信传送"小文件"到服务器 [c#源码分享]客户端程序通过TCP通信传送"小文件"到服务器 源码  (不包含通信框架源码,通信框架源码请另行 ...

  7. WinForm播放视频

    原文:WinForm播放视频 1背景 这几天一老友要求我做个小软件,在WinForm播放视频.印象中微软有个WM控件直接可以使用,晚上研究下 2实现方式 2.1微软草根 最简单的方式,是直接使用微软的 ...

  8. Linux页快速缓存与回写机制分析

    參考 <Linux内核设计与实现> ******************************************* 页快速缓存是linux内核实现的一种主要磁盘缓存,它主要用来降低 ...

  9. asp.net读取CSV

    原文:asp.net读取CSV 用Excel导了两天数据,各种问题,折磨客户也折磨了自己,以前没发现的问题一下子都暴露出来了 特意收集两篇Excel跟CSV读取相关的两篇文章 asp.net读取exc ...

  10. CSS中选择器优先级顺序实战讲解

    原文:CSS中选择器优先级顺序实战讲解 我们有些程序猿在给一个元素(比如div)应用样式的时候,会有一些疑问,为什么我写在后面的样式不能覆盖前面的样式呢,不是说CSS是层叠样式表吗? 如果你在开发中也 ...