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

worldblog發表於2007-12-04
STL的內觀排序(introsort)演算法學習筆記 (轉)[@more@]

 

STL(Standard Template Library)的演算法據說是經過精心的。那麼在它的排序演算法方面做了哪些最佳化呢?


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


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


void quicksort(_RanIterator __start, _RandomIterator __last)
{
  while (__last - __first > __stl_threshold) {
  _RandomIterator __pivot= partition(__first, __last, mean(*__first, *__last, *(__first + (__last-__first)/2));
  quicksort(__first, __pivot);
  __first = __pivot;
  }
  __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_l(RandomIterator __first, RandomIterator __last, int m)
{
 while (__last - __first > __stl_threshold) {
 if (0==m) {
 partial_sort(__first, __last, __last);
 return;
 }
 RandomIterator __pivot = mean(*__first, *__last, *(__first+(__last-__first)/2));
 introsort__loop(__first, __pivot);
 __first = __pivot+1;
 }
}
void introsort(RandomIterator __first, RandomIterator __last)
{
 introsort_loop(__first, __last, __lg(__last-__first)*2);
 __final_insert_sort(__first, __last);
}


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

void __final_insert_sort(__first, __last)
{
 if (__last - __first < __stl_threshold)
 __insert_sort(__first, __last);
 else {
 __insert_sort(__first, __first+__stl_threshold);
 __unguarded_insert_sort(__first+__std_threshold+1, __last);
 }
}

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


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988340/,如需轉載,請註明出處,否則將追究法律責任。

相關文章