STL sort
STL的sort()算法,数据量大时采用Quick Sort,分段递归排序,一旦分段后的数据量小于某个门槛,为避免Quick Sort的递归调用带来过大的额外负荷,就改用Insertion Sort。如果递归层次过深,还会改用Heap Sort。本文先分别介绍这个三个Sort,再整合分析STL sort算法(以上三种算法的综合) -- Introspective Sorting(内省式排序)。
一、Insertion Sort
Insertion Sort
// 默认以渐增方式排序
template <class RandomAccessIterator>
void __insertion_sort(RandomAccessIterator first,
RandomAccessIterator last)
{
if (first == last) return;
// --- insertion sort 外循环 ---
for (RandomAccessIterator i = first + 1; i != last; ++i)
__linear_insert(first, i, value_type(first));
// 以上,[first,i) 形成一个子区间
}
template <class RandomAccessIterator, class T>
inline void __linear_insert(RandomAccessIterator first,
RandomAccessIterator last, T*)
{
T value = *last; // 记录尾元素
if (value < *first){ // 尾比头还小 (注意,头端必为最小元素)
copy_backward(first, last, last + 1); // 将整个区间向右移一个位置
*first = value; // 令头元素等于原先的尾元素值
}
else // 尾不小于头
__unguarded_linear_insert(last, value);
}
template <class RandomAccessIterator, class T>
void __unguarded_linear_insert(RandomAccessIterator last, T value)
{
RandomAccessIterator next = last;
--next;
// --- insertion sort 内循环 ---
// 注意,一旦不再出现逆转对(inversion),循环就可以结束了
while (value < *next){ // 逆转对(inversion)存在
*last = *next; // 调整
last = next; // 调整迭代器
--next; // 左移一个位置
}
*last = value; // value 的正确落脚处
}
二、Quick Sort
Quick Sort
// 返回 a,b,c之居中者
template <class T>
inline const T& __median(const T& a, const T& b, const T& c)
{
if (a < b)
if (b < c) // a < b < c
return b;
else if (a < c) // a < b, b >= c, a < c --> a < b <= c
return c;
else // a < b, b >= c, a >= c --> c <= a < b
return a;
else if (a < c) // c > a >= b
return a;
else if (b < c) // a >= b, a >= c, b < c --> b < c <= a
return c;
else // a >= b, a >= c, b >= c --> c<= b <= a
return b;
}
Partitioning(分割)
Partitioning
template <class RandomAccessIterator, class T>
RandomAccessIterator __unguarded_partition(
RandomAccessIterator first,
RandomAccessIterator last,
T pivot)
{
while(true){
while (*first < pivot) ++first; // first 找到 >= pivot的元素就停
--last;
while (pivot < *last) --last; // last 找到 <=pivot
if (!(first < last)) return first; // 交错,结束循环
// else
iter_swap(first,last); // 大小值交换
++first; // 调整
}
}
三、Heap Sort
Heap Sort
// paitial_sort的任务是找出middle - first个最小元素。
template <class RandomAccessIterator>
inline void partial_sort(RandomAccessIterator first,
RandomAccessIterator middle,
RandomAccessIterator last)
{
__partial_sort(first, middle, last, value_type(first));
}
template <class RandomAccessIterator,class T>
inline void __partial_sort(RandomAccessIterator first,
RandomAccessIterator middle,
RandomAccessIterator last, T*)
{
make_heap(first, middle); // 默认是max-heap,即root是最大的
for (RandomAccessIterator i = middle; i < last; ++i)
if (*i < *first)
__pop_heap(first, middle, i, T(*i), distance_type(first));
sort_heap(first,middle);
}
四、IntroSort
Intro Sort
template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first,
RandomAccessIterator last)
{
if (first != last){
__introsort_loop(first, last, value_type(first), __lg(last-first)*2);
__final_insertion_sort(first,last);
}
}
// __lg()用来控制分割恶化的情况
// 找出2^k <= n 的最大值,例:n=7得k=2; n=20得k=4
template<class Size>
inline Size __lg(Size n)
{
Size k;
for (k = 0; n > 1; n >>= 1)
++k;
return k;
}
// 当元素个数为40时,__introsort_loop的最后一个参数
// 即__lg(last-first)*2是5*2,意思是最多允许分割10层。
const int __stl_threshold = 16;
template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first,
RandomAccessIterator last, T*,
Size depth_limit)
{
while (last - first > __stl_threshold){ // > 16
if (depth_limit == 0){ // 至此,分割恶化
partial_sort(first, last, last); // 改用 heapsort
return;
}
--depth_limit;
// 以下是 median-of-3 partition,选择一个够好的枢轴并决定分割点
// 分割点将落在迭代器cut身上
RandomAccessIterator cut = __unguarded_partition
(first, last, T(__median(*first,
*(first + (last - first)/2),
*(last - 1))));
// 对右半段递归进行sort
__introsort_loop(cut,last,value_type(first), depth_limit);
last = cut;
// 现在回到while循环中,准备对左半段递归进行sort
// 这种写法可读性较差,效率也并没有比较好
}
}
template <class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first,
RandomAccessIterator last)
{
if (last - first > __stl_threshold){
// > 16
// 一、[first,first+16)进行插入排序
// 二、调用__unguarded_insertion_sort,实质是直接进入插入排序内循环,
// *参见Insertion sort 源码
__insertion_sort(first,first + __stl_threshold);
__unguarded_insertion_sort(first + __stl_threshold, last);
}
else
__insertion_sort(first, last);
} template <class RandomAccessIterator>
inline void __unguarded_insertion_sort(RandomAccessIterator first,
RandomAccessIterator last)
{
__unguarded_insertion_sort_aux(first, last, value_type(first));
} template <class RandomAccessIterator, class T> void __unguarded_insertion_sort_aux(RandomAccessIterator first,
RandomAccessIterator last,
T*)
{
for (RandomAccessIterator i = first; i != last; ++i)
__unguarded_linear_insert(i, T(*i));
}
if (last - first > __stl_threshold){ // > 16
...
...
__introsort_loop(cut,last,value_type(first), depth_limit);
__introsort_loop(first,cut,value_type(first), depth_limit);

STL sort的更多相关文章
- STL sort 函数实现详解
作者:fengcc 原创作品 转载请注明出处 前几天阿里电话一面,被问到STL中sort函数的实现.以前没有仔细探究过,听人说是快速排序,于是回答说用快速排序实现的,但听电话另一端面试官的声音,感觉不 ...
- STL sort()函数
C++之所以得到这么多人的喜欢,是因为它既具有面向对象的概念,又保持了C语言高效的特点.STL 排序算法同样需要保持高效.因此,对于不同的需求,STL提供的不同的函数,不同的函数,实现的算法又不尽相同 ...
- STL::sort函数实现
声明:本文参考链接:STL::sort实现. 排序是面试中经常被问及的算法基础知识点,虽然实际应用中不会直接使用,但是理解这些简单的算法知识对于更复杂更实用的算法有一定的帮助,毕竟面试总不能问的太过深 ...
- STL sort 函数实现详解 ZZ
前几天阿里电话一面,被问到STL中sort函数的实现.以前没有仔细探究过,听人说是快速排序,于是回答说用快速排序实现的,但听电话另一端面试官的声音,感觉不对劲,知道自己回答错了.这几天特意看了一下,在 ...
- c++ stl sort example
c++ stl sort函数使用举例: #include <iostream> #include<vector> #include<algorithm> #incl ...
- c++ STL sort struct comp
详细解说 STL 排序(Sort) http://www.cppblog.com/mzty/archive/2005/12/15/1770.html 详细解说 STL 排序(Sort) 作者Winte ...
- 分享stl sort函数坑点导致coredump问题
在<Effective STL> 的条款21中就有讨论:永远让比较函数对相同元素返回false! 也就是说在实现stl sort函数自定义比较器时,一定要满足这种严格弱序化的问题.
- STL sort源码剖析
转载自:http://www.cnblogs.com/imAkaka/articles/2407877.html STL的sort()算法,数据量大时采用Quick Sort,分段递归排序,一旦分段后 ...
- STL——sort函数简介
参考:http://blog.csdn.net/s030501408/article/details/5329477 0)与C标准库qsort的比较:http://bbs.csdn.net/topic ...
随机推荐
- 20165202 实验一 Java开发环境的熟悉
一.实验内容及步骤 (一)使用JDK编译.运行简单的Java程序 建立"自己学号exp1"的目录 mkdir 20165202exp1 进入目录 cd 20165202exp1 在 ...
- 慕课网-Linux达人养成计划学习笔记
mkdir -p [目录]创建目录-p 递归创建ls 查看当前目录下的文件和目录等其他文件 cd [目录]命令英文愿意:change directory切换所在目录简化操作cd ~ 进入当前用户的家目 ...
- Python程序员不完全指南
Python 基础 Python基础 基础数据类型 深浅copy 文件操作 函数 初识函数 函数进阶 装饰器函数 迭代器和生成器 各种推导式 递归函数 内置函数和匿名函数 异常处理 常用模块 模块和包 ...
- 一个好工具-everything-可以找到浏览器的所有缓存
下载路径http://www.voidtools.com/downloads/ 我用它来寻找浏览器缓存的google瓦片.
- 《Drools7.0.0.Final规则引擎教程》第4章 4.6 结果条件
结果条件 在Java中,如果有重复的代码我们会考虑进行重构,抽取公共方法或继承父类,以减少相同的代码在多处出现,达到代码的最优管理和不必要的麻烦.Drools同样提供了类似的功能.下面我们以实例来逐步 ...
- Unity 2d 的 SpriteMask为游戏表现带来多种可能性
孙广东 2017.7.22 http://blog.csdn.NET/u010019717 SpriteMask 是Unity 2017.1 开始添加2d功能!, Spri ...
- iOS如何限制使用SDK的版本? 解决iOS项目的版本兼容问题
更新 2015-11-16 感谢微博好友@zyyy_000的评论,补充了为什么要在+ (void)load方法里面做Method Swizzling. 前言 最近,在做项目时,因为某种原因,突然要 ...
- jquery.treetable.js
html: <table class="table table-hover table-responsive main-list" id="columntabl ...
- 用户空间与内核驱动的交互过程 — ioctl
在Linux内核模块的开发过程中,经常涉及到运行在用户空间上的应用程序与内核模块进行交互,ioctl系统调用是常用的一种方式.本文并不涉及vlan的具体原理,仅通过vconfig与vlan内核模块进行 ...
- FreeMarker自定义TemplateDirectiveModel
[参考:http://blog.csdn.net/fangzhangsc2006/article/details/8687371] 在采用FreeMarker做前台视图模板的情况下,我们可以通过< ...