http://blog.csdn.net/whuslei/article/details/6442755web
排序算法通過了很長時間的演變,產生了不少種不一樣的方法。對於初學者來講,對它們進行整理便於理解記憶顯得很重要。每種算法都有它特定的使用場合,很難通用。所以,咱們頗有必要對全部常見的排序算法進行概括。算法
我不喜歡死記硬背,我更偏向於弄清前因後果,理解性地記憶。好比下面這張圖,咱們將圍繞這張圖來思考幾個問題。shell
上面的這張圖來自一個PPT。它歸納了數據結構中的全部常見的排序算法。如今有如下幾個問題:數據結構
一、每一個算法的思想是什麼?
二、每一個算法的穩定性怎樣?時間複雜度是多少?
三、在什麼狀況下,算法出現最好狀況 or 最壞狀況?
四、每種算法的具體實現又是怎樣的?spa
這個是排序算法裏面最基本,也是最常考的問題。下面是個人小結。.net
1、直接插入排序(插入排序)。3d
一、算法的僞代碼(這樣便於理解): orm
INSERTION-SORT (A, n) A[1 . . n]
for j ←2 to n
do key ← A[ j]
i ← j – 1
while i > 0 and A[i] > key
do A[i+1] ← A[i]
i ← i – 1
A[i+1] = keyblog
二、思想:以下圖所示,每次選擇一個元素K插入到以前已排好序的部分A[1…i]中,插入過程當中K依次由後向前與A[1…i]中的元素進行比較。若發現發現A[x]>=K,則將K插入到A[x]的後面,插入前須要移動元素。排序
三、算法時間複雜度。
最好的狀況下:正序有序(從小到大),這樣只須要比較n次,不須要移動。所以時間複雜度爲O(n)
最壞的狀況下:逆序有序,這樣每個元素就須要比較n次,共有n個元素,所以實際複雜度爲O(n­2)
平均狀況下:O(n­2)
四、穩定性。
理解性記憶比死記硬背要好。所以,咱們來分析下。穩定性,就是有兩個相同的元素,排序前後的相對位置是否變化,主要用在排序時有多個排序規則的狀況下。在插入排序中,K1是已排序部分中的元素,當K2和K1比較時,直接插到K1的後面(沒有必要插到K1的前面,這樣作還須要移動!!),所以,插入排序是穩定的。
五、代碼(c版) blog.csdn.com/whuslei
2、希爾排序(插入排序)
一、思想:希爾排序也是一種插入排序方法,其實是一種分組插入方法。先取定一個小於n的整數d1做爲第一個增量,把表的所有記錄分紅d1個組,全部距離爲d1的倍數的記錄放在同一個組中,在各組內進行直接插入排序;而後,取第二個增量d2(<d1),重複上述的分組和排序,直至所取的增量dt=1(dt<dt-1<…<d2<d1),即全部記錄放在同一組中進行直接插入排序爲止。
例如:將 n 個記錄分紅 d 個子序列:
{ R[0], R[d], R[2d],…, R[kd] }
{ R[1], R[1+d], R[1+2d],…,R[1+kd] }
…
{ R[d-1],R[2d-1],R[3d-1],…,R[(k+1)d-1] }
說明:d=5 時,先從A[d]開始向前插入,判斷A[d-d],而後A[d+1]與A[(d+1)-d]比較,如此類推,這一回合後將原序列分爲d個組。<由後向前>
二、時間複雜度。
最好狀況:因爲希爾排序的好壞和步長d的選擇有不少關係,所以,目前尚未得出最好的步長如何選擇(如今有些比較好的選擇了,但不肯定是不是最好的)。因此,不知道最好的狀況下的算法時間複雜度。
最壞狀況下:O(N*logN),最壞的狀況下和平均狀況下差很少。
平均狀況下:O(N*logN)
三、穩定性。
因爲屢次插入排序,咱們知道一次插入排序是穩定的,不會改變相同元素的相對順序,但在不一樣的插入排序過程當中,相同的元素可能在各自的插入排序中移動,最後其穩定性就會被打亂,因此shell排序是不穩定的。(有個猜想,方便記憶:通常來講,若存在不相鄰元素間交換,則極可能是不穩定的排序。)
四、代碼(c版) blog.csdn.com/whuslei
3、冒泡排序(交換排序)
一、基本思想:經過無序區中相鄰記錄關鍵字間的比較和位置的交換,使關鍵字最小的記錄如氣泡通常逐漸往上「漂浮」直至「水面」。
二、時間複雜度
最好狀況下:正序有序,則只須要比較n次。故,爲O(n)
最壞狀況下: 逆序有序,則須要比較(n-1)+(n-2)+……+1,故,爲O(N*N)
三、穩定性
排序過程當中只交換相鄰兩個元素的位置。所以,當兩個數相等時,是不必交換兩個數的位置的。因此,它們的相對位置並無改變,冒泡排序算法是穩定的!
四、代碼(c版) blog.csdn.com/whuslei
4、快速排序(交換排序)
一、思想:它是由冒泡排序改進而來的。在待排序的n個記錄中任取一個記錄(一般取第一個記錄),把該記錄放入適當位置後,數據序列被此記錄劃分紅兩部分。全部關鍵字比該記錄關鍵字小的記錄放置在前一部分,全部比它大的記錄放置在後一部分,並把該記錄排在這兩部分的中間(稱爲該記錄歸位),這個過程稱做一趟快速排序。
說明:最核心的思想是將小的部分放在左邊,大的部分放到右邊,實現分割。
二、算法複雜度
最好的狀況下:由於每次都將序列分爲兩個部分(通常二分都複雜度都和logN相關),故爲 O(N*logN)
最壞的狀況下:基本有序時,退化爲冒泡排序,幾乎要比較N*N次,故爲O(N*N)
三、穩定性
因爲每次都須要和中軸元素交換,所以原來的順序就可能被打亂。如序列爲 5 3 3 4 3 8 9 10 11會將3的順序打亂。因此說,快速排序是不穩定的!
5、直接選擇排序(選擇排序)
一、思想:首先在未排序序列中找到最小元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小元素,而後放到排序序列末尾。以此類推,直到全部元素均排序完畢。具體作法是:選擇最小的元素與未排序部分的首部交換,使得序列的前面爲有序。
二、時間複雜度。
最好狀況下:交換0次,可是每次都要找到最小的元素,所以大約必須遍歷N*N次,所以爲O(N*N)。減小了交換次數!
最壞狀況下,平均狀況下:O(N*N)
三、穩定性
因爲每次都是選取未排序序列A中的最小元素x與A中的第一個元素交換,所以跨距離了,極可能破壞了元素間的相對位置,所以選擇排序是不穩定的!
6、堆排序
一、思想:利用徹底二叉樹中雙親節點和孩子節點之間的內在關係,在當前無序區中選擇關鍵字最大(或者最小)的記錄。也就是說,以最小堆爲例,根節點爲最小元素,較大的節點偏向於分佈在堆底附近。
二、算法複雜度
最壞狀況下,接近於最差狀況下:O(N*logN),所以它是一種效果不錯的排序算法。
三、穩定性
堆排序須要不斷地調整堆,所以它是一種不穩定的排序!
7、歸併排序
一、思想:屢次將兩個或兩個以上的有序表合併成一個新的有序表。
二、算法時間複雜度
最好的狀況下:一趟歸併須要n次,總共須要logN次,所以爲O(N*logN)
最壞的狀況下,接近於平均狀況下,爲O(N*logN)
說明:對長度爲n的文件,需進行logN 趟二路歸併,每趟歸併的時間爲O(n),故其時間複雜度不管是在最好狀況下仍是在最壞狀況下均是O(nlgn)。
三、穩定性
歸併排序最大的特點就是它是一種穩定的排序算法。歸併過程當中是不會改變元素的相對位置的。
四、缺點是,它須要O(n)的額外空間。可是很適合於多鏈表排序。
五、代碼(略)blog.csdn.com/whuslei
8、基數排序
一、思想:它是一種非比較排序。它是根據位的高低進行排序的,也就是先按個位排序,而後依據十位排序……以此類推。示例以下:
二、算法的時間複雜度
分配須要O(n),收集爲O(r),其中r爲分配後鏈表的個數,以r=10爲例,則有0~9這樣10個鏈表來將原來的序列分類。而d,也就是位數(如最大的數是1234,位數是4,則d=4),即"分配-收集"的趟數。所以時間複雜度爲O(d*(n+r))。
三、穩定性
基數排序過程當中不改變元素的相對位置,所以是穩定的!
四、適用狀況:若是有一個序列,知道數的範圍(好比1~1000),用快速排序或者堆排序,須要O(N*logN),可是若是採用基數排序,則能夠達到O(4*(n+10))=O(n)的時間複雜度。算是這種狀況下排序最快的!!
五、代碼(略)
總結: 每種算法都要它適用的條件,本文也僅僅是回顧了下基礎。若有不懂的地方請參考課本。