STLは、ソートのソースコードを解析します

序文

- 「STLのソースコード解析」から仕上げ本論文では、
ソースコードは古い解析されているがが、核となるアイデアはあまり変化しなかった、あまりにも多くの詳細はソースを直接見があります私は、最新のを理解していません

簡単な紹介

ソート2受け入れるRandomAccessIterators第二のバージョンは、ユーザは、ソート基準としてSTL型容器関係の全てをファンクタを指定することができ、その後、セクション内のすべての要素が徐々に再配置ZOに方法を昇順、(イテレータランダムアクセスメモリ)自動ソート機能は必要ありません持っているソートスタックキュー優先キューは、特別な入り口があり、ソートが許可されていない、と休息のベクトルを両端キューおよびリストの両方属しイテレータの前に、RandomAccessIteratorsソート用、およびリスト反復子それが属するBidirectionalIteratorsを

データの量STLソートアルゴリズム、クイックソート例として避けるために、一度、再帰ソートセグメント、セグメントのデータ量が所定の閾値よりも小さくなっているクイックソートスイッチ上であまりにも多くの付加的な負荷を引き起こす再帰呼び出しを挿入ソート深すぎる再帰のレベルは、使用する場合は、ヒープにソートを

挿入ソート

template <class RandomAccessIterator>
void __insertion_sort (RandomAccessIterator first,
                        RandomAccessIterator last){
   if(first == last) return;
   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);
      *fist = 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 的内循环
   //一旦不出现逆序对循环即可结束
   while(value < *next){ //逆序对存在
      *last = *next;     //调整
      last = next;      //调整迭代器
      --next;//左移一个位置
   }
   *last = value; //把value的值移动到正确的
}
         

一般的なので、上記の機能がunguarded_xという名前の理由は、ソート、挿入内部ループのニーズの2人の隣人が「逆順」であるかどうか二度の判断を行わなければ
、最低保証を含め、だけでなく、範囲外のかどうかを判断するために、今避けられません最もエッジ層の部分区間は、そう一度、合成された時間内のデータのこの大量の、実行時間はかなり驚くべきこと。

unguarded_xと同様の理由を命名した後。

中央・オブ・スリー(三点中央値)

//返回 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
            return c;
        else
            return a;
    else if (a < c) // c > a >=b
        return a;
    else if (b < c)  //a >= b, a >= c, b < c
        return c;
    return b;
}

パーティショニング(分割)

右分割位置の後に値を返す提供SGIのSTLパーティション関数:

//版本一 
template <class RandomAccessIterator, class T>
RandomAccessIterator __unguarded_partition(RandomAccessIterator first,
    RandomAccessIterator last,
    T pivot) {
    while (true) {
        --last;
        while (*first < *last) ++first; //first 找到 >= pivot的元素就停下来
        --last;  //调整
        while (pivot < *last) --last; //last找到 <= pivot 的元素就停下来
        //一下first<last 判断操作只适用于 random iterator
        if (!(first < last)) return first; //交错,结束循环
            iter_swap(fist, last);//大小值交换
        ++first;//调整
    }
}

スレッショルド(しきい値)

要素の数十の小さなシリーズの顔だけは、使用クイックソートソートの多くを必要とするかもしれないような複雑な操作価値がない、少量のデータの場合のように、でも簡単な挿入ソートそれはより速いかもしれソートクイック -なぜならクイックソートの再帰関数呼び出しの多くを生成した配列については最小限になります。
したがって、適切な評価と最適化アルゴリズムの必要性。

最終挿入ソート

最適化の施策決してあまり、限り、我々は軽率に行動しないと。我々は次のシーケンスの住居「ほとんどソートされたが、完了していない」で特定のサイズを加えた場合の状態、そして最終的に一度に挿入ソート、すべて「ほとんど結実に彼の作品を並べ替えではなく、」シーケンスが完了ソートを行うには、その効率は一般よりも良いと考えられている「完全にソートされたすべてのサブシーケンス。」これは、挿入ソート順序の顔に「ほとんどソート」、および良好な性能を持っています。

イントロソート

ピボット不適切な選択はにつながる、不適切なセグメント化につながることができ、クイックソート急速に悪化。デビッドR.マッサー1996年にハイブリッドソートアルゴリズムを提案した内省ソート、(内省ソート)が呼ばInstroSort上記と同様、ほとんどの場合、その挙動をするが、傾向及び二次挙動の挙動に分割したとき自己検出、それによってに切り替えソート・ヒープ効率でそれらを維持するために、ヒープ・ソートは O(NlogN)です。

//版本一
//千万注意:sort()只适用于RandomAccessIterator
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 的最大k 例如: n = 7,得 k=2, n=20,得k=4,n=8,得k=3
template<class Size>
inline Size __lg(Size n) {
    Size k;
    for (k = 0; n > 1; n >= 1) ++k;
    return k;
}

    //当元素个数为40时,__introsort_loop()的最后一个参数将是5*2,意思是最多允许分割10层。

次のようにイントロソートアルゴリズムは次のとおりです。

//版本一
//注意,本函数内的许多迭代器运算操作,都只适用于RandomAccess Iterators
template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first,
    RandomAccessIterator last, T*,
    Size depth_limit) {
    //以下, __stl_threshold 是个全局阐述,稍早定义为 const int 16
    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
        //这种写法可读性差,效率并没有比较好
        // RW STL , 采用一般教科书写法(直观地对左半段和右半段递归),较易阅读
    }
}

機能開始シーケンスの決意サイズ、__次のようにグローバル整数Uを生成stl_thresholdが、定義される:
const int __stl_threshold = 16 ;
レベルが分割規定値を超えた場合、セグメンテーションのレベルをチェックし、要素数の後にチェックすることにより(このIは、テキストの前の段落で行いました説明)、部分的に切り替える_sort()、psrtial_sort()ソートヒープ行います。

すべてのこれらのテストの後、我々は入りますソートクイックを正確に同じ手順を:ピボット中央値-の-3方式の位置を決定するために:その後、分割ポイントを見つけるために、_unduarded_pa​​rtition()を呼び出し、その後、段落再帰程度のためにイントロソート

各サブシーケンス内__introsort_loop [最初、最後の「要素の16未満の数」のシーケンス番号()の端部)は、要素の数ので回未満(かなりのソーティング成都を有しているが、まだ完全にソートされていない場合親関数へ戻る__stl_threshold、さらなる動作はソート終了する)、ソート()、再び入る__final_insertion_sort()。

//版本一
template <class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first,
    RandomAccessIterator last)
{
    if (last - first > __stl_threshold) { // >16
        __insertion_sort(first, first + __stl_threshold);
        __unguarded_insertion_sort(first + __stl_threshold, last);
    }
    __insertion_sort(first, last);
}

この関数は、最初の答えはない__inertion_sort()が呼び出され処理されるべきではない場合答えが肯定である場合の要素の数は、16よりも大きいか否かを判断し、それに[最初、最後)の分割された長さ16のサブシーケンスの期間、および残りの他の断片サブシーケンス、及び2つのサブシーケンス__insertiong_sort()を要求及び__unguarded_insertion_sort(それぞれ)、前者は次のようにコードはソースを通じて実証されています。

//版本一
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));
}

これは、()のソースコードの上部に次のRWのSTLのソートを比較するために、ソートのSGIのSTLの励磁部である
純粋でRWバージョンをクイックソートはないイントロソート

RWのSTLのソート()

template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first,
    RandomAccessIterator last)
{
    if (!(first == last))
    {
        __quick_sort_loop(first, last);
        __final_insertion_sort(first, last);
    }
}

template <class RandomAccessIterator>
inline void __quick_soort_loop(RandomAccessIterator first,
    RandomAccessIterator last)
{
    __quick_soort_loop_aux(first, last, _RWSTD_VALUE_TYPE(first));
}

template <class RandomAccessIterator,class T>
void __quick_sort_loop_aux(RandomAccessIterator first,
    RandomAccessIterator last,
    T*)
{
    while (last - first > __stl_threshold)
    {
        //median-of-3 partitioning
        RandomAccessIterator cut = __unguarded_partition(first, last, T(__median(*first, *(first + (last - first) / 2), *(last - 1)));
        if (cut - first >= last - cut)
        {
            __quick_soort_loop(cut, last);//对右段递归处理
            last = cut;
        }
        else
        {
            __quick_sort_loop(first,cut);
            first = cut;
        }
    }
}

おすすめ

転載: www.cnblogs.com/shcnee/p/12233580.html