STL的內觀排序 introsort 演算法學習筆記

2021-06-10 02:58:23 字數 1413 閱讀 1991

stl(standard template library)的演算法據說是經過精心優化的。那麼在它的排序演算法方面做了哪些優化呢?

自從快速排序演算法出世以後,從平均效能上來說,除了在資料量極少(<=20)的的情況下其效能不如插入排序外,快速演算法的效能起碼是其他同階演算法的2到3倍,這也已經是教科書裡不爭的事實。

乙個最簡單的混合演算法就是在資料量少的時候(n<20),演算法轉入插入排序,而其它時候則仍然採用快速排序,比如

void quicksort(_randomiterator __start, _randomiterator __last)

__insert_sort(__first, __last);

}這裡有乙個選擇,就是什麼時候做插入排序:上面的演算法是每次細分到資料量小於閾值就轉入插入排序;另外一種演算法是一旦細分到資料長度小於閾值就退出,最後彙總的時候再來一次總的插入排序。應該說這兩種演算法沒有很大的區別,但是stl使用的是後者。原因最後再說。

stl真正出彩的地方是對快速排序演算法的補充。快速 排序的特點是平均效能好,能達到o(nlgn)的效能,缺點是對於最壞情況效能會下降到o(n^2)。stl對此做的補充是引入乙個遞迴計數,當遞迴深度超過一定閾值(stl設定的閾值是2lgn),則演算法轉入乙個較慢的但是最壞情況也是o(nlgn)的演算法,比如堆排序(stl把堆排序推廣為partial_sort也就是部分排序)。這一演算法監控自身的遞迴深度,具有一定的內觀性,被稱為內觀排序(introsort--introspective sort),實際上是快速排序法的變種,是一種混合演算法。在最壞情況下能近似達到o(nlgn)的效能。實際上在最壞情況下比堆排序要差點,但是比快速排序要好得多。而其平均效能和快速排序差不多。其演算法如下:

void introsort_loop(randomiterator __first, randomiterator __last, int m)

randomiterator __pivot = mean(*__first, *__last, *(__first+(__last-__first)/2));

introsort__loop(__first, __pivot);

__first = __pivot+1;}}

void introsort(randomiterator __first, randomiterator __last)

stl在__final_inser_sort中玩了乙個小小的加速trick。其演算法如下:

void __final_insert_sort(__first, __last)

}我當時不太明白為什麼插入演算法還要如此,後來自己嘗試優化插入演算法的時候才發現在__unguarded_insert_sort的迴圈中少了乙個邊界測試條件,這樣邊界測試條件從兩個降為乙個。原因就是經過「粗略的」快速排序後,最小元素已經能確定就在前__stl_threshold個元素中,於是基於位置的邊界條件就可以去掉。具體參看插入排序的演算法。不再贅述。

Introsort 內觀排序

net 4.5 這個版本的array.sort更改了stl的內觀排序演算法,那相對於快速排序內觀排序到底有什麼優化過的呢?根據維基百科所說,這個排序演算法首先從快速排序開始,當遞迴深度超過一定深度 深度為排序元素數量的對數值 後轉為堆排序。採用這個方法,introsort既能在常規資料集上實現快速排...

Shuffle內的排序

排序重點 implements writablecomparable 繼承writablecomparable介面 並重寫裡面的方法實現排序 三個方法 compareto write readfields保證輸出是完整的 全域性排序 reducer 10 9 5 3 2 1 只有乙個reduce為了...

STL 排序的相關函式

1 sort 這個就不用說了吧。最快的乙個,一般都用它。2 stable sort 以前沒看到過?這個保證了排序前後相等元素之間的相對位置不發生改變。這對於內建型別的預設比較方式來說沒什麼用 相等就相等,改變了也沒用 但對於結構體,或者傳入了比較函式的就有用了,它保證了排序前後 相等 元素的相對位置...