1. 程式人生 > >《STL原始碼剖析》Sort排序分析

《STL原始碼剖析》Sort排序分析

整體而言: sort演算法在資料量大時採用Quick Sort(快速排序),一旦分段後的資料量小於某個門檻,為避免Quick Sort的遞迴呼叫帶來過大的額外負擔,就改用Insertion Sort(插入排序),如果遞迴層次過深,還會改用Heap Sort(堆排序),先分別簡單介紹Quick Sort

Insertion Sort插入排序

Insertion sort以雙層迴圈的形式進行,外迴圈便利整個序列,每次迭代決定出一個自區間,內迴圈遍歷自區間,將自區間內的沒一個“逆轉對”倒轉過來。所謂“逆轉對”是指任何兩個迭代器i,j,i

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,Random AccessIterator last
,T*){ T value=*last;//記錄尾元素 if(value<*first){ copy_backward(first,last,last+1);//將整個區間拷貝 *first=value; } else//尾不小於頭 __unguarded_linear_insert(last,value); } template<class RandomAccessIterator,class T> void __unguarded_linear_insert(RandomAccessIterator first,Random AccessIterator last
,T value){ RandomAccessIterator next=last; --next; //insertion sort的內迴圈 //注意,一旦不再出現逆轉對,迴圈就可以結束了 while(value<*next){//逆轉對存在 *last==*next; last=nex; --next; } *last=value; }

Quick Sort快速排序

Quick Sort是目前已知的最快的排序法,平均複雜度為O(NlogN),最壞情況下將達O(N²)。不過IntroSort(非常類似於median-of-three QuickSort的一種排序演算法)可將最壞情況推進到O(NlogN)。早期的STLsort演算法都採用QuickSort,SGI STL已經改用IntroSort。
median-of-three(三點之中值):任意一個元素都可以被送來當樞軸(pivot),但其合適與否將影響QuickSort的效率,為了避免“元素當初輸入時不夠隨機”所帶來的惡化效應,最理想的最穩當的方法就是取整個序列的頭、尾、中央三個位置的元素,以其中值作為樞軸,這種做法成為median-of-three partitioning,或成為median-of-QuickSort,為了能夠快速取出中央位置的元素,顯然迭代器必須能夠快速取出中央位置的元素,顯然迭代器必須能夠隨機讀取,亦即是個RandomAccessIterators。

final insertion sort

sort採用的優化方案,即前面的所有排序步驟都採用QuickSOrt,只有最後一次採用insertionSort,因為insertionSort在面對“幾近排序”的序列時,能擁有很好的表現。

Inrtosort(Introspective sorting,內省式排序)

其行為在大部分情況下幾乎與median-of-three Quick Sort完全相同(當然也就一樣快,但是當分割行為有惡化為二次行為的傾向時,能夠自我檢測,轉而改用Heap Sort,使得效率維持在HeapSort的O(NlogN),又比一開始就用HeapSort來得好。