STL学习笔记之sort算法

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。

 

点赞