常見排序算法總結

本篇博客是《大話數據結構》第9章排序部分的學習筆記,部分圖文參考國外博客

排序算法的穩定性:對於值相等的元素,排序前後的相對位置不發生改變,則稱該排序算法爲穩定的排序。

內排序與外排序:根據在排序過程中待排序的記錄是否全部被放置在內存中分爲內排序和外排序。

根據排序算法中藉助的主要操作,可把內排序分爲:插入排序、交換排序、選擇排序和歸併排序。

根據排序算法的複雜性(非時間複雜度)可將其分爲簡單排序算法和改進算法。其中簡單排序算法包括冒泡排序、簡單選擇排序、直接插入排序。改進算法包括希爾排序、堆排序、歸併排序、快速排序。

1.冒泡排序

基本思想:以遞增排序進行說明,若有N個元素需要排序,每趟排序從頭開始兩兩比較相鄰元素的大小,將大的那個放到後面,則每趟結束都把最大的那個找了出來。N個元素的話需要進行N-1趟排序,第i趟排序需要進行N-i次比較。

冒泡排序

改進:設立Flag,當某一趟未發生交換時,排序即可終止。

時間複雜度分析:

最好的情況就是序列本身有序,那麼進行1趟(n-1)次比較,發現沒有數據交換排序即可終止,時間複雜度爲O(n)。

最壞的情況就是逆序,比較n-1趟,每趟比較n-i次,比較次數總共爲(n-1)+(n-2)+...+4+3+2+1=n(n-1)/2次,移動次數也這麼多。時間複雜度爲O(n^2)

平均時間複雜度:O(n^2)

2.簡單選擇排序

由於 冒泡排序的思想是通過不斷地交換從而完成最終排序,操作非常頻繁。那能不能減少交換次數,只在找到合適的值時才進行交換完成排序呢?這就是選擇排序的基本思想。在冒泡和選擇排序之間一般選選擇排序。

基本思想:每一趟在n-i+1(i=1,2,...,n-1)個記錄中選取關鍵字最小的記錄作爲有序序列的第i個記錄。也就是相當於將輸入列表/數組分爲兩部分:已經排序的子列表和剩餘要排序的子列表。不斷在未排序的子列表中找到最小的元素,並將其與第一個未排序的元素進行交換。此過程重複進行,直到列表完全排序。需要記錄已排序列表的末尾。下圖所示中每次未排序列表中的最小值與豎線右邊的第一個進元素行交換。

選擇排序

時間複雜度:

無論最好還是最壞情況,比較的次數都是一樣多的。第i趟排序需要進行n-i次關鍵字的比較,共比較n-1趟,總次數爲n(n-1)/2次。對於交換次數而言,最好的情況下,交換0次。書上說最壞的情況,即降序的情況,交換次數爲n-1次(不是的吧,這個如果是降序排序的話,只用交換n/2次向下取整就可以了,因爲交換是對稱的)。排序時間是比較與交換次數的總和,因此總的時間複雜度依然爲O(n^2)。

儘管與冒泡排序同爲O(n^2),但簡單選擇排序的性能還是略優於冒泡排序。

3.直接插入排序

基本思想:就是理撲克牌的思想。基本操作是將一個記錄插入到已經排好序的有序表中,從而得到一個新的、記錄數增1的有序表。需要設置哨兵暫存當前的值,與已排序好的列表進行比較從而找到哨兵在其中的位置。主循環從i=2開始,默認第一個元素在已排序序列中。

插入排序

時間複雜度:

最好的情況是本身有序,比較的次數爲n-1次,不需要移動,時間複雜度爲O(n)。

最壞的情況是本身逆序如{6,5,4,3,2},需要比較n-1次,移動......時間複雜度爲O(n^2)

4.快速排序

基本思想:通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序的目的。

快速排序

主要的步驟如下:

(1)我們首先選擇一個元素,稱爲數組的基準元素(pivot)。
(2)將所有小於基準元素的元素移動到基準元素的左側;將所有大於基準元素的元素移動到基準元素的右側。

(3)遞歸地將上述兩個步驟分別應用於比上一個基準元素值更小和更大的元素的每個子數組。

時間複雜度分析:

如果用遞歸樹來描述算法的執行情況,

在最優情況下,Partition每次都劃分得很均勻,遞歸樹的深度就位log2(n)向下取整+1,即僅需遞歸log2(n)次,需要時間爲T(n)的話,第一次Partition應該需要對整個數組掃描一遍,做n次比較,然後獲得的pivot將數組一分爲二,那麼各自還需要T(n/2)的時間(注意是最好情況,所以平分兩半)。如下圖所示,最優情況快排的時間複雜度爲O(nlogn)。

在最壞情況下,待排序的序列爲正序或者逆序,每次劃分只得到一個比上一次劃分少一個記錄的子序列,另一個爲空。O(n^2)。

平均情況下,O(nlogn)。

空間複雜度分析:

就空間複雜度來說,主要是遞歸造成的棧空間的使用,最好情況,遞歸樹的深度爲log2n,其空間複雜度也就爲0([logn),最壞情況,需要進行n-1遞歸調用,其空間複雜度爲0(n),平均情況,空間複雜度也爲0([logn)。
 

快速排序的優化:

1.關於pivot(樞軸)的選擇:隨機選取樞軸/三數取中(左端、右端、中間三個數進行排序,取中間的那個數)/九數取中(從數組中分三次取樣,每次取三個各取出中值,再從這三個中值中取出一箇中值)。

2.優化不必要的交換:將pivot備份到L.r[0]中,採用替換而不是交換的方式進行操作。

3.如果數組很小,快排反而不如直接插入排序來得好。直接插入是簡單排序中性能最好的。由於快排用到了遞歸操作,在大量數據排序時比較快,但是少量數據時反而沒那麼好。因此加入判斷,當high-low不大於某個常數時,就使用直接插入排序。

4.優化遞歸操作,實施尾遞歸優化。

 

5.歸併排序

基本思想:

歸併排序

(1)連續劃分未排序列表,直到有N個子列表,其中每個子列表有1個“未排序”元素,N是原始數組中的元素數。
(2)重複合併,即一次將兩個子列表合併在一起,生成新的排序子列表,直到所有元素完全合併到一個排序數組中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章