sort函数的研究
来源:互联网 发布:网络被攻击怎么解决 编辑:程序博客网 时间:2024/05/12 17:55
一.实现原理
原来,STL中的sort并非只是普通的快速排序,除了对普通的快速排序进行优化,它还结合了插入排序和堆排序。根据不同的数量级别以及不同情况,能自动选用合适的排序方法。当数据量较大时采用快速排序,分段递归。一旦分段后的数据量小于某个阀值,为避免递归调用带来过大的额外负荷,便会改用插入排序。而如果递归层次过深,有出现最坏情况的倾向,还会改用堆排序。
普通的快速排序
普通快速排序算法可以叙述如下,假设S代表需要被排序的数据序列:
1.如果S中的元素只有0个或1个,结束。
2.取S中的任何一个元素作为枢轴pivot。
3.将S分割为L、R两端,使L内的元素都小于等于pivot,R内的元素都大于等于pivot。
4.对L、R递归执行上述过程。
快速排序最关键的地方在于枢轴的选择,最坏的情况发生在分割时产生了一个空的区间,这样就完全没有达到分割的效果。STL采用的做法称为median-of-three,即取整个序列的首、尾、中央三个地方的元素,以其中值作为枢轴。
分割的方法通常采用两个迭代器head和tail,head从头端往尾端移动,tail从尾端往头端移动,当head遇到大于等于pivot的元素就停下来,tail遇到小于等于pivot的元素也停下来,若head迭代器仍然小于tail迭代器,即两者没有交叉,则互换元素,然后继续进行相同的动作,向中间逼近,直到两个迭代器交叉,结束一次分割。
看一张来自维基百科上关于快速排序的动态图片,帮助理解。
内省式排序 Introsort
不当的枢轴选择,导致不当的分割,会使快速排序恶化为 O(n2)。David R.Musser于1996年提出一种混合式排序算法:Introspective Sorting(内省式排序),简称IntroSort,其行为大部分与上面所说的median-of-three Quick Sort完全相同,但是当分割行为有恶化为二次方的倾向时,能够自我侦测,转而改用堆排序,使效率维持在堆排序的 O(nlgn),又比一开始就使用堆排序来得好。*
二.代码分析
下面是完整的SGI STL sort()源码(使用默认<操作符版)
template <class _RandomAccessIter>inlinevoid sort(_RandomAccessIter __first, _RandomAccessIter __last) { __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator); __STL_REQUIRES(typename iterator_traits<_RandomAccessIter>::value_type, _LessThanComparable); if (__first != __last) { __introsort_loop(__first, __last, __VALUE_TYPE(__first), __lg(__last - __first) * 2); __final_insertion_sort(__first, __last); }}
其中,__introsort_loop便是上面介绍的内省式排序,其第三个参数中所调用的函数__lg()便是用来控制分割恶化情况,代码如下:
template <class Size>inline Size __lg(Size n) { Size k; for (k = 0; n > 1; n >>= 1) ++k; return k;}
即求lg(n)(取下整),意味着快速排序的递归调用最多 2*lg(n) 层。
内省式排序算法如下:
template <class _RandomAccessIter, class _Tp, class _Size>void __introsort_loop(_RandomAccessIter __first, _RandomAccessIter __last, _Tp*, _Size __depth_limit){ while (__last - __first > __stl_threshold) { if (__depth_limit == 0) { partial_sort(__first, __last, __last); return; } --__depth_limit; _RandomAccessIter __cut = __unguarded_partition(__first, __last, _Tp(__median(*__first, *(__first + (__last - __first)/2), *(__last - 1)))); __introsort_loop(__cut, __last, (_Tp*) 0, __depth_limit); __last = __cut; }}
1.首先判断元素规模是否大于阀值__stl_threshold,__stl_threshold是一个常整形的全局变量,值为16,表示若元素规模小于等于16,则结束内省式排序算法,返回sort函数,改用插入排序。
2.若元素规模大于__stl_threshold,则判断递归调用深度是否超过限制。若已经到达最大限制层次的递归调用,则改用堆排序。代码中的partial_sort即用堆排序实现。
3.若没有超过递归调用深度,则调用函数__unguarded_partition()对当前元素做一趟快速排序,并返回枢轴位置。__unguarded_partition()函数采用的便是上面所讲的使用两个迭代器的方法,代码如下:
template <class _RandomAccessIter, class _Tp>_RandomAccessIter __unguarded_partition(_RandomAccessIter __first, _RandomAccessIter __last, _Tp __pivot) {while (true) { while (*__first < __pivot) ++__first; --__last; while (__pivot < *__last) --__last; if (!(__first < __last)) return __first; iter_swap(__first, __last); ++__first;}}
4.经过一趟快速排序后,再递归对右半部分调用内省式排序算法。然后回到while循环,对左半部分进行排序。源码写法和我们一般的写法不同,但原理是一样的,需要注意。
递归上述过程,直到元素规模小于__stl_threshold,然后返回sort函数,对整个元素序列调用一次插入排序,此时序列中的元素已基本有序,所以插入排序也很快。至此,整个sort函数运行结束。
以上摘自:http://www.cnblogs.com/LonelyEnvoy/p/6258171.html
相关用法
1.sort中cmp的参数类型为值,返回类型为bool,比较过程用>和<,升序为a
#include<algorithm>#include<iostream>#include<cmath>using namespace std;int cmp( const int &a, const int &b );int main(){ int a[11]={2,4,1,23,5,76,0,43,24,65},i; for( i=0;i<10;i++) cout<<a[i]<<endl; sort(a,a+10,cmp); for( i=0;i<10;i++) cout<<a[i]<<endl; return 0;}int cmp( const int &a, const int &b ){ if( a > b ) return 1;/// a<b就是升序排列 else return 0;}
是先按x升序排序,若x值相等则按y升序排
该用法在hd的一道题用到
int cmp( const POINT &a, const POINT &b ){ if( a.x < b.x ) return 1; else if( a.x == b.x ) { if( a.y < b.y ) return 1; else return 0; } else return 0;}sort(a,a+n,cmp);
- sort函数的研究
- sort函数的用法
- sort函数的用法
- Sort函数的用法
- sort函数的用法
- sort函数的用法
- sort函数的用法
- Sort函数的用法
- sort函数的用法
- STL的sort函数
- sort函数的使用
- sort函数的用法
- sort函数的用法
- sort函数的使用
- sort函数的用法
- python的 sort()函数
- sort 函数的用法
- sort函数的用法
- C++ rvalue赋值运算符定义
- Python requests 模拟登陆
- 锂电池为啥会爆炸
- 使用junit Assert 断言来判断参数是否为空
- HTML_多媒体效果_embed标签详解
- sort函数的研究
- 在mac系统安装Apache Tomcat的详细步骤
- codeforces-758【B、C思维】
- 大数据发展及岗位分析
- java.io
- epoll详解
- 第 1 章 Node.js 介绍
- js cookie简单操作
- 解决eclipse配置Tomcat时找不到server选项(Mac通用)