STL的sort函数浅析

用了这么久的sort,大概知道它是快排加一些其他排序组合起来的一个排序算法,今天就来捋清楚。

直接上图片:

sort定义在stl_algo.h里,看起来只不过是对另一个函数的封装。

 __sort函数也定义在stl_algo.h里:

可以看到它首先判断左右迭代器是否指代有效区间,如果不是有效区间就直接返回。

如果有效:先调用一个__introsort_loop算法,再调用__final_insertion_sort算法。

__introsort_loop算法是什么呢:

其中的_S_threshold是一个枚举值,等于16。

 

也就是当区间长度大于16的时候,才会进入循环。否则直接返回之前的__sort函数里执行__final_insertion_sort算法。

循环内部:每次__depth_limit先减1,然后:

_RandomAccessIterator __cut =
        std::__unguarded_partition_pivot(__first, __last, __comp);

unguarded_partition_pivot这个名字显然是个快排的划分算法,返回一个随机迭代器__cut代表切分点,我们点进去看看:

 

 可以看到其把区间中点和起始点进行了交换,应该是为了随机化处理,防止快速排序退化为n^2。之后调用另一个划分函数__unguarded_partition:

 嗯。。看起来就是个划分函数,没有再深入的必要了。那么我们回到__introsort_loop函数:

 黄线这行将区间first到last做了一次划分,划分点为cut。然后调用了自己:调用的参数区间为cut到last,也就是右半部。注意这里是尾递归。

递归过程先不考虑,假设执行完这次递归调用后,即我们对cut到last执行完了一次__introsort_loop函数。

然后将__last的值赋为__cut,这样下次循环我们对左区间继续划分。

继续循环,__depth_limit继续减1,显然经过有限次循环,最终__depth_limit会等于0。

这时执行if语句:

 __partial_sort函数:

 看起来就是一个堆排序算法,没什么特别的,就不深入看了。

回到之前的if语句,调用完这个堆排序算法后,我们的__introsort_loop函数就退出了。

这样我们又回到了__sort函数:

 下面的__final_insertion_sort显然是个插入排序算法,我们也不用深入看了。

至此,整个__sort函数完毕,也就是我们的排序算法到此结束了。

总结一下:

STL的sort函数会先调用一个__introsort_loop算法,其实这个算法有名字,叫做内省排序:https://baike.baidu.com/item/%E5%86%85%E7%9C%81%E6%8E%92%E5%BA%8F/6471937?fr=aladdin

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

和我们观察结果是一样的:当区间长度大于16的时候,进行递归快排。

如果达到递归层数限制,改为调用堆排序并返回。

如果区间长度小于16了,改为调用插入排序。

这样的好处是:

到了最后一步,整个序列已经基本被排列好了,也就是排序程度很高,但没有完全排序,所以在这里我们只用了插入排序,这样的效率更好。

说的不对可以评论指出,欢迎转载,标明出处哦~

猜你喜欢

转载自www.cnblogs.com/FdWzy/p/12521238.html