stl所提供的各式各样的算法中,sort()是最复杂庞大的一个。这个算法接受两个随机存取迭代器,然后将区间内的所有元素以渐增方式由小到大重新排列。还有个版本则允许用户指定一个仿函数,作为排序标准。
stl中的所有关系型容器都拥有自动排序功能,所以不需要sort算法。序列式容器中的stack,deque和priority_queue都有特别的入口,不允许用户对元素排序。剩下的vector,deque和list,list或slist应该使用它们自己提供的成员函数sort()。也就是说,只有vector和deque适合使用sort算法。
stl中的sort算法,数据量大时采用quick sort,分段递归排序。一旦分段后的数据量小于某个门槛,为避免quick sort的递归调用带来过大的额外负荷,就改用insertion sort。如果递归层次过深,还会改用heap sort。SGI STL中,基于此种考虑的sort算法称为introspective sort,即IntroSort。
对于IntroSort,我想有两个问题需要弄清:
1,当数据量小到什么程度时,使用insertion sort?
2,当递归层次多深时,改用heap sort?
我们可以先看看IntroSort的源码实现:
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()用来控制分割恶化的情况
template<class Size>
inline Size __lg(Size n){
Size k;
for(k = 0; n>1; n >>=1) ++k; //找出2^k<=n的最大k
return k;
}
template<class RandomAccessIterator, class T, class Size >
void __introsort_loop(RandomAccessIterator first,
RandomAccessIterator last,
T*,
Size depth_limit) {
while(last - first > __stl_threshold){ //__stl_threshold为全局整型常数16
if(depth_limit == 0) {
partial_sort(first, last, last);//恶化,改用heap sort,partial_sort是以heap sort完成的
return;
}
--depth_limit;
RandomAccessIterator cut = __ungruarded_partion(first,
last,
T(__median(*first,
(first + (last-first)/2)
*(last - 1))));
//对右半段递归进行sort
__introsort_loop(cut, last, value_type(first), depth_limit);
last = cut; //这种写法可读性较差,回到while循环,准备对左半段进行递归。
}
}
template <class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first,
RandomAccessIterator last) {
if(last - first > __stl_threshold) {
__insertion_sort(first, first+__stl_threshold);
__unguarded_insertion_sort(first + __stl_threshold, last);
}
else
__insertion_sort(first, last);
}
总结下这段代码的意思:如果数据量小于16,则直接使用insert sort;若数据量大于16,且没有超过最大递归深度(2*logn),则采用quick sort,将所有元素分成size小于16的数据段,最后采用insert sort整体排序(基本有序的情况下,insert sort效率很高);若递归深度超过最大递归深度,则这部分数据采用heap sort。
在RW版的STL中,sort算法采用的是纯粹的quick sort。