1. 程式人生 > >各種內排序演算法的C++實現(不斷更新中)

各種內排序演算法的C++實現(不斷更新中)

      和很多計算機系的同學們一樣,我在大學二年級時也學了《資料結構》這門課。當時我的老師是一箇中科大的博士,現在已經是教授了。他在課上曾經這樣評價這門課:《資料結構》幾乎是所有計算機課程的基礎課,如果把這門課學好了,其他的專業課就不成問題了。還有,IT公司的面試經常涉及到資料結構的相關知識,該課程的重要性由此可見。但是當時年少無知根本沒好好學習,等到筆試,面試時才幡然悔悟。下面的內排序演算法可算是資料結構中的重要內容,程式程式碼全部用C++實現,已在visual C++6.0上執行過了。

一.插入排序(insert sorting)

最差情況下,直接插入排序的最大時間代價為θ(n²),最小時間代價為θ(n),平均時間代價為θ(n²)。

   

二.氣泡排序(bubble sorting)

氣泡排序的最大時間代價,最小時間代價和平均時間代價均為θ(n²)。

   

三.選擇排序(selection sorting)

 選擇排序的最大時間代價,最小時間代價和平均時間代價均為θ(n²)。選擇排序不依賴於原始陣列的輸入順序。

   

四.shell sorting

增量為2的shell排序的時間代價可以達到θ(n的3/2次方),有的增量可以達到θ(n的7/6次方),很接近θ(n)。

   

五.快速排序(quick sorting)

快速排序的最大時間代價為θ(n²),最小時間代價為θ(n*logn),平均時間代價為θ(n*logn)。注意:快速排序是一種不穩定的排序方式,其效能依賴於原始陣列的有序程度,更進一步分析,就是依賴與軸值元素的選擇。快排的比較次數遠多於移動次數,所以主要考慮比較次數。
 快排中,每一次比較可以確定一個軸值元素的位置。若p[m,q,n](q為軸值元素)。當然確定第一個軸值元素也是要比較(n-m-1)次。但第二個軸值元素,第三個軸值元素就要進行(q-m-1)和(n-q-1)次比較。如果q的值若為m或n,快速排序就退化成氣泡排序了,快排就沒有什麼優勢了。

  

六.歸併排序(merge sorting)

歸併排序的最大時間代價,最小時間代價和平均時間代價均為θ(n*logn)。歸併排序不依賴於原始陣列的有序程度。

  

七.堆排序(heap sorting)

堆排序的最大時間代價,最小時間代價和平均時間代價均為θ(n*logn)。堆排序和歸併排序一樣,不依賴於原始陣列的有序程度。

HeapSorting.cpp

  

MaxHeap.h

  

MaxHeap.cpp

  

八.基數排序(radix sorting)

基數排序的時間複雜度為O (nlog(r)m),其中r為所採取的基數,而m為堆數,在某些時候,基數排序法的效率高於其它的比較性排序法。基數排序法是屬於穩定性的排序。

   

     下面我們來討論一下各種排序演算法的穩定度,穩定排序演算法會依照相等的關鍵(換言之就是值)維持紀錄的相對次序。也就是一個排序演算法是穩定的,就是當有兩個有相等關鍵的紀錄R和S,且在原本的串列中R出現在S之前,在排序過的串列中R也將會是在S之前。

  一般的方法:插入、交換、選擇、合併等等。交換排序包含氣泡排序(bubble sort)和快速排序(quicksort)。選擇排序包含shaker排序和堆排序(heapsort)。

  當相等的元素是無法分辨的,比如像是整數,穩定度並不是一個問題。然而,假設以下的數對將要以他們的第一個數字來排序。

  (4, 1) (3, 1) (3, 7) (5, 6)

  在這個狀況下,有可能產生兩種不同的結果,一個是依照相等的鍵值維持相對的次序,而另外一個則沒有:

  (3, 1) (3, 7) (4, 1) (5, 6) (維持次序)

  (3, 7) (3, 1) (4, 1) (5, 6) (次序被改變)

  不穩定排序演算法可能會在相等的鍵值中改變紀錄的相對次序,但是穩定排序演算法從來不會如此。不穩定排序演算法可以被特別地時作為穩定。作這件事情的一個方式是人工擴充鍵值的比較,如此在其他方面相同鍵值的兩個物件間之比較,就會被決定使用在原先資料次序中的條目,當作一個同分決賽。然而,要記住這種次序通常牽涉到額外的空間負擔。

穩定的排序演算法:

      氣泡排序(bubble sort) — O(n2)

  雞尾酒排序 (Cocktail sort, 雙向的氣泡排序) — O(n2)

  插入排序 (insertion sort)— O(n2)

  桶排序 (bucket sort)— O(n); 需要 O(k) 額外 記憶體

  歸併排序 (merge sort)— O(n log n); 需要 O(n) 額外記憶體

  原地歸併排序 — O(n2)

  二叉樹排序 (Binary tree sort) — O(n log n); 需要 O(n) 額外記憶體

  基數排序 (radix sort)— O(n·k); 需要 O(n) 額外記憶體

不穩定的排序演算法:

      選擇排序 (selection sort)— O(n2)

    希爾排序 (shell sort)— O(n log n) 如果使用最佳的現在版本

  Comb sort — O(n log n)

  堆排序 (heapsort)— O(n log n)

  Smoothsort — O(n log n)

  快速排序 (quicksort)— O(n log n) 期望時間, O(n2) 最壞情況; 對於大的、亂數串列一般相信是最快的已知排序

      一般來說:存在不相鄰交換的排序演算法是不穩定的,相鄰交換的排序演算法是穩定的;對於相鄰交換的穩定排序演算法,通過控制交換條件可以轉換成不穩定排序演算法;冒泡、插入、歸併和基數排序是穩定的;選擇、快速、希爾和堆排序是不穩定的。