經常使用的排序算法總結

經常使用排序算法總結html

排序算法大致可分爲兩種:算法

一種是比較排序,時間複雜度O(nlogn) ~ O(n^2),主要有:冒泡排序選擇排序插入排序歸併排序堆排序快速排序等。api

另外一種是非比較排序,時間複雜度能夠達到O(n),主要有:計數排序基數排序桶排序等。數組

1. 經常使用的比較排序算法性能

 

 

 

有一點咱們很容易忽略的是排序算法的穩定性(騰訊校招2016筆試題曾考過)。排序算法穩定性的簡單形式化定義爲:若是Ai=Aj,排序前Ai在Aj以前,排序後Ai還在Aj以前,則稱這種排序算法是穩定的通俗地講就是保證排序先後兩個相等的數的相對順序不變。設計

對於不穩定的排序算法,只要舉出一個實例,便可說明它的不穩定性;而對於穩定的排序算法,必須對算法進行分析從而獲得穩定的特性。須要注意的是,排序算法是否爲穩定的是由具體算法決定的,不穩定的算法在某種條件下能夠變爲穩定的算法,而穩定的算法在某種條件下也能夠變爲不穩定的算法。指針

例如,對於冒泡排序,本來是穩定的排序算法,若是將記錄交換的條件改爲A[i] >= A[i + 1],則兩個相等的記錄就會交換位置,從而變成不穩定的排序算法。htm

其次,說一下排序算法穩定性的好處。排序算法若是是穩定的,那麼從一個鍵上排序,而後再從另外一個鍵上排序,前一個鍵排序的結果能夠爲後一個鍵排序所用。基數排序就是這樣,先按低位排序,逐次按高位排序,低位排序後元素的順序在高位也相同時是不會改變的。blog

 

(1)   冒泡排序排序

思想:重複地走訪過要排序的元素,依次比較相鄰兩個元素,若是他們的順序錯誤就把他們調換過來,直到沒有元素再須要交換,排序完成。這個算法的名字由來是由於越小(或越大)的元素會經由交換慢慢「浮」到數列的頂端。

算法步驟

1.比較相鄰的元素,若是前一個比後一個大,就把它們兩個調換位置。

2.對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對。這步作完後,最後的元素會是最大的數。

3.針對全部的元素重複以上的步驟,除了最後一個。

4.持續每次對愈來愈少的元素重複上面的步驟,直到沒有任何一對數字須要比較。

 

Python代碼:

 

 

 

 

(2)   選擇排序

思想:初始時在序列中找到最小(大)元素,放到序列的起始位置做爲已排序序列;而後,再從剩餘未排序元素中繼續尋找最小(大)元素,放到已排序序列的末尾。以此類推,直到全部元素均排序完畢。

 

Python代碼

 

 

 

選擇排序是不穩定的排序算法,不穩定發生在最小元素與A[i]交換的時刻。

好比序列:{ 5, 8, 5, 2, 9 },一次選擇的最小元素是2,而後把2和第一個5進行交換,從而改變了兩個元素5的相對次序。

 

(3)   插入排序

思想:很是相似於咱們抓撲克牌,對於未排序數據(右手抓到的牌),在已排序序列(左手已經排好序的手牌)中從後向前掃描,找到相應位置並插入。

 

算法步驟:

1.從第一個元素開始,該元素能夠認爲已經被排序

2.取出下一個元素,在已經排序的元素序列中從後向前掃描

3.若是該元素(已排序)大於新元素,將該元素移到下一位置

4.重複步驟3,直到找到已排序的元素小於或者等於新元素的位置

5.將新元素插入到該位置後

6.重複步驟2~5

 

Python代碼:

 

 

 

 

插入排序不適合對於數據量比較大的排序應用。可是,若是須要排序的數據量很小,好比量級小於千,那麼插入排序仍是一個不錯的選擇。 插入排序在工業級庫中也有着普遍的應用,在STL的sort算法和stdlib的qsort算法中,都將插入排序做爲快速排序的補充,用於少許元素的排序(一般爲8個或如下)。

 

插入排序的改進1:二分插入排序

對於插入排序,若是比較操做的代價比交換操做大的話,能夠採用二分查找法來減小比較操做的次數,咱們稱爲二分插入排序,代碼以下:

 

 

 

當n較大時,二分插入排序的比較次數比直接插入排序的最差狀況好得多,但比直接插入排序的最好狀況要差,所當以元素初始序列已經接近升序時,直接插入排序比二分插入排序比較次數少。二分插入排序元素移動次數與直接插入排序相同,依賴於元素初始序列。

 

(4)   希爾排序(插入排序的更高效的改進)

希爾排序是基於插入排序的如下兩點性質而提出改進方法的:

1.插入排序在對幾乎已經排好序的數據操做時,效率高,便可以達到線性排序的效率

2.但插入排序通常來講是低效的,由於插入排序每次只能將數據移動一位

 

思想:經過將比較的所有元素分爲幾個區域來提高插入排序的性能。這樣可讓一個元素能夠一次性地朝最終位置前進一大步。而後算法再取愈來愈小的步長進行排序,算法的最後一步就是普通的插入排序,可是到了這步,需排序的數據幾乎是已排好的了(此時插入排序較快)。

 

Python代碼:

 

 

 

希爾排序是不穩定的排序算法,雖然一次插入排序是穩定的,不會改變相同元素的相對順序,但在不一樣的插入排序過程當中,相同的元素可能在各自的插入排序中移動,最後其穩定性就會被打亂。

好比序列:{ 3, 5, 10, 8, 7, 2, 8, 1, 20, 6 },h=2時分紅兩個子序列 { 3, 10, 7, 8, 20 } 和  { 5, 8, 2, 1, 6 } ,未排序以前第二個子序列中的8在前面,如今對兩個子序列進行插入排序,獲得 { 3, 7, 8, 10, 20 } 和 { 1, 2, 5, 6, 8 } ,即 { 3, 1, 7, 2, 8, 5, 10, 6, 20, 8 } ,兩個8的相對次序發生了改變。

 

(5)   歸併排序

思想:歸併排序的實現分爲遞歸實現與非遞歸(迭代)實現。遞歸實現的歸併排序是算法設計中分治策略的典型應用,咱們將一個大問題分割成小問題分別解決,而後用全部小問題的答案來解決整個大問題。非遞歸(迭代)實現的歸併排序首先進行是兩兩歸併,而後四四歸併,而後是八八歸併,一直下去直到歸併了整個數組

歸併排序算法主要依賴歸併(Merge)操做。歸併操做指的是將兩個已經排序的序列合併成一個序列的操做,歸併操做步驟以下:

1.申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列

2.設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置

3.比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置

4.重複步驟3直到某一指針到達序列尾

5.將另外一序列剩下的全部元素直接複製到合併序列尾

Python代碼(遞歸實現):

 

 

 

 

(6)   堆排序

堆是一種近似徹底二叉樹的結構(一般堆是經過一維數組來實現的),並知足性質:以最大堆(也叫大根堆、大頂堆)爲例,其中父結點的值老是大於它的孩子節點。

 

算法步驟:

1.由輸入的無序數組構造一個最大堆,做爲初始的無序區

2.把堆頂元素(最大值)和堆尾元素互換

3.把堆(無序區)的尺寸縮小1,並調用heapify(A, 0)重新的堆頂元素開始進行堆調整

4.重複步驟2,直到堆的尺寸爲1

 

堆排序是不穩定的排序算法,不穩定發生在堆頂元素與A[i]交換的時刻。

好比序列:{ 9, 5, 7, 5 },堆頂元素是9,堆排序下一步將9和第二個5進行交換,獲得序列 { 5, 5, 7, 9 },再進行堆調整獲得{ 7, 5, 5, 9 },重複以前的操做最後獲得{ 5, 5, 7, 9 }從而改變了兩個5的相對次序。

 

 

Python代碼:

 

 

 

 

(7)   快速排序

快速排序使用分治策略來把一個序列分爲兩個子序列。步驟爲:

1.從序列中挑出一個元素,做爲」基準」(pivot).

2.把全部比基準值小的元素放在基準前面,全部比基準值大的元素放在基準的後面(相同的數能夠到任一邊),這個稱爲分區(partition)操做。

3.對每一個分區遞歸地進行步驟1~2,遞歸的結束條件是序列的大小是0或1,這時總體已經被排好序了。

 

Python代碼:

 

 

 

快速排序是不穩定的排序算法,不穩定發生在基準元素與A[tail+1]交換的時刻。

好比序列:{ 1, 3, 4, 2, 8, 9, 8, 7, 5 },基準元素是5,一次劃分操做後5要和第一個8進行交換,從而改變了兩個元素8的相對次序。

 

參考博客:https://www.cnblogs.com/sunbingqiang/p/9033447.html

相關文章
相關標籤/搜索