写在前面
Q:什么容器适合sort()算法?
A:vector, deque
- 关系型容器的底层采用红黑树,具有自动排序的功能,不需用sort()算法
- 序列式容器中的stack,queue,priority_queue都有特别的出入口,不允许对元素进行排序;list的迭代器属于BidirectionIterator(双向迭代器),而sort算法的迭代器属于RandomAccessIterator(随机存取迭代器),list自己定义了相应的成员函数来实现排序
sort()算法
参考链接:https://zhuanlan.zhihu.com/p/36274119
STL的sort()算法涉及到了三种排序算法:快排、直接插入、堆排
快排的时间复杂度为O(nlogn),但是在最坏的情况下(在分隔时出现子区间为空的情况),快排的时间复杂度达到O(n^2),此时递归的层数也会越来越深。在数据量小的情况下,数据基本有序时,采用直接插入排序比快排更快。
堆排的时间复杂度恒为O(nlogn),无论数据有什么特征它的时间复杂度是不变的,虽然时间复杂度和快排相同,当时总体来说没有快排的速度快,主要原因在于,堆排涉及到大量的交换操作。
为了避免快排恶化到O(n^2)的时间复杂度,当递归的层数达到一定值时,转而采用堆排序。
当数据量小于某个值(SGI STL中设定的是16)时,采用直接插入排序
代码实现:
- 快排的基准值采用:三点中值,也就是序列的首元素、尾元素以及中间元素这三者的中值
1.sort函数
__lg函数:计算对数
2.__introsort_loop涉及到快排和堆排
当递归深度大于depth_limit时,采用堆排partial_sort
快排分隔函数__unguarded_partition:
快排基准值选取函数__median
3.__final_insertion_sort涉及到插入排序
当序列长度不大于16时采用插入排序
如果长度不大于16,直接调用插入排序的函数__insertion_sort,否则将前16个元素进行插入排序,后面的元素通过循环调用插入排序的内层循环处理函数__unguarded_linear_insert()处理
补充:插入排序
总结
sort()算法的过程:
- 算法中涉及到两个阈值,子序列的长度(程序中设定为16),递归的深度(2logn)
- 首先如果序列的长度大于16调用快排函数进行处理,否则直接进行插入排序
- 快排处理的过程中需要判断递归的深度,当递归的深度超过阈值时,采用堆排进行处理
- 快排过程结束后,此时元素已基本有序,采用直接插入进行处理