c++ sort解读


c++ 中 sort函数的具体实现在不同编译器下不同,本篇代码来自msvc编译器,版本号14.24.28314

函数原型

首先可以看到sort函数有两个原型,如下,

template <class RandomAccessIterator>
  void sort (RandomAccessIterator first, RandomAccessIterator last);

template <class RandomAccessIterator, class Compare>
  void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

第一个函数是将[first,last)之间的元素按照升序排序,实质上是第二个函数的一个特例,即
comp=less<>()的情况。这在代码中也可以得到验证,第一个函数中实际上直接对第二个函数进行了调用,代码如下:

template <class _RanIt>
void sort(const _RanIt _First, const _RanIt _Last) { // order [_First, _Last), using operator<
    _STD sort(_First, _Last, less<>());
} 

另外,需要说明的是,sort是一种不稳定排序,若要使用稳定排序,请使用函数stable_sort.

不稳定排序: 对于值相等的元素,排序时不保证不改变其序列。举个简单的例子。新学期开始了,男女生要按照高矮个排队,小明和小亮
一样高,本来小明在小亮前边位置正好可以和班花同桌 ,可是按照高矮个排序之后,小明竟然和小亮的位置交换了。这就是不稳定排序。

sort代码

下边便是sort函数的实现代码,先不执着于细节,可以看出sort中使用了三种排序算法:快速排序,堆排序和插入排序。

template <class _RanIt, class _Pr>
void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) {
    // order [_First, _Last), using _Pred
    _Iter_diff_t<_RanIt> _Count;
    while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal) { // divide and conquer by quicksort
        auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred);
        // TRANSITION, VSO#433486
        _Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions
                                                // 约等于 1.26不是1.5,难道是我错了?

        if (_Mid.first - _First < _Last - _Mid.second) { // loop on second half
            _Sort_unchecked(_First, _Mid.first, _Ideal, _Pred);
            _First = _Mid.second;
        } else { // loop on first half
            _Sort_unchecked(_Mid.second, _Last, _Ideal, _Pred);
            _Last = _Mid.first;
        }
    }

    if (_ISORT_MAX < _Count) { // heap sort if too many divisions
        _Make_heap_unchecked(_First, _Last, _Pred);
        _Sort_heap_unchecked(_First, _Last, _Pred);
    } else if (2 <= _Count) {
        _Insertion_sort_unchecked(_First, _Last, _Pred); // small
    }
}

快速排序阶段

尽管sort最终的排序不是快速排序完成的,但是排序开始阶段首先进行的是快速排序。即上边代码中while循环部分,也可以看出此处的快速排序
是通过递归实现的。

快速排序:通过一趟排序将要排序的数据分割成独立的两部分,
其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序

快速排序的平均时间复杂度为 O ( n l o g n ) O(nlogn) ,可是在最坏情况下会是 O ( n 2 ) O(n^2) ,这就是复杂度恶化。怎么防止复杂度恶化呢?
可以在某种触发条件下进入堆排序或插入排序过程。其中堆排序不是必然进入的。

堆排序阶段

正如上边说的,堆排序不是必然进入的一个过程,只有一种情况下会进入堆排序,即0 == _Ideal,_Ideal这个变量用于控制
递归深度,注释中说将递归深度控制在1.5 log2(N) ,我算了下是约等于1.26不是1.5,难道是我算错了?

插入排序

对于区间宽度小于等于_ISORT_MAX时,进入插入排序阶段,这是排序的最后阶段。其中,

// COMMON SORT PARAMETERS
const int _ISORT_MAX = 32; // maximum size for insertion sort

插入排序适用于已经有部分数据已经排好,并且排好的部分越大越好,因此在排序的最后阶段选用了插入排序作为终结。

猜你喜欢

转载自blog.csdn.net/iceboy314159/article/details/105891676