1. 程式人生 > >常用排序演算法原理總結

常用排序演算法原理總結

前面有篇文章總結了效能,同時強調了演算法原理才是最重要的,僅僅記住一些效能指標的資料,是沒有用的。這篇文章主要以較“精煉簡單”但是又“詳細囉嗦”的語言來描述演算法實現的細節過程!注意:可能不適合初學者看,初學者應該先看演算法書籍以及實現的原始碼,然後再參考下文敘述來幫助理解演算法實際的原理!本篇沒有例項程式碼,請參看《大話資料結構》的C原始碼和個人的github的java原始碼連結!(《大話資料結構》java語言實現

一、簡單排序
1、冒泡:起始時,從最後一個數字開始逐個與前面的數字比較(小則替換,大則不替換),直至確定當前的索引號的位置;(外迴圈確定當前索引號,內迴圈執行冒泡比較)
  冒泡plus:

新增一個標誌位,用來記錄上一次外迴圈比較的時候是否發生交換,如果沒發生交換,說明已經排序好了,以後的外迴圈排序就沒有必要了,所以直接跳出就可以了!

2、簡單選擇:起始時,規定當前外迴圈的索引號為最小值,然後後續數字都和這個最小值比較,直到比較完後,確定新的最小值,然後才交換(注意比較的時候不交換);繼續迴圈,確定下一個索引號的最小值;(PS:其實就是找最小值然後插入0位,然後再找剩下的最小值(即第二最小)插入1位,依次類推,和冒泡不同的是,冒泡每次從後邊往前面比較而且都交換,然後“冒”上來!這個是從前往後比找到最小值最後才交換)

3、直接插入:起始時選擇i=2位置的記錄值作為比較物件(i=0為哨兵位)並快取至i=0位,然後開始從i-1位->0位元素逐個與當前資料比較(已經快取到0位了,其實也就是和0位比較),比它大則說明i-1位不應該在當前i位的左側,所以後移,直到遇到比它小或者等於(等於的時候比較到0位了)的則退出比較。此時空出的位置就是i=2記錄值的新位置,以此類推;
  直接插入plus:

從倒數第二個開始比較,即首先取出n-1位,並快取!從n-2->0位順序開始比較,比它大則後移,比它小則停止比較,把快取的當前的資料插入到此時空出的位置,重新快取當前比它小的資料,以此類推 !(PS:原理都是一樣的,但是從後往前比其實邏輯更好理解)

4、希爾排序:參見直接插入,只不過希爾排序不是-1的比較,而是-n的比較(PS:希爾排序也是插入排序,都是先快取當前位資料!只不過希爾排序每次從-1位開始開始和當前位比較,然後步進為-1向前進軍;希爾排序首先就從-n位開始當前位比較,然後步進為-n向前進軍。二者都是遇到比它大的數字,然後大數字後移,當然後移的位置也是1位和n位的差別!還有就是n並不是一個定值,比如建議n=n/3+1,n初始值為序列長,經過這個計算後才是第一次用到的步進值!當序列遍歷到最後一個節點的時候(初始化從n+1開始遍歷),則再次計算n值)

二、高階排序:
5、堆排序:構造堆——首先把序列看成是一個層序遍歷的二叉樹,然後起始點預設是length/20,開始比較所在的根節點和子節點大小(共三個數字記錄),把最大的數字記錄交換為當前根節點,然後依次類推變成一個大頂堆(假設length=9,則分別把(4,9)(3,9)(2,9)(1,9)變成大頂堆);排序——把堆低的數字記錄(末尾)和root節點交換,然後繼續構造剩餘資料記錄(即(1,8)(1,7)(1,6)…..)的大頂堆,以此類推直到最後排序完成。

6、歸併排序:拆分歸併——首先會把序列進行遞迴拆分,直到出現拆分過後當前棧內首位=末尾,則跳出迴圈繼續遞迴拆分上一個棧的另半邊序列,再跳出迴圈開始歸併比較!在跳出迴圈進入下一輪左拆分、右拆分、歸併的步驟,直到最後比較完!排序——歸併思想很簡單,就是找到一個輔助空間(這裡是輔助陣列),然後分別比較原來兩個序列當前位置的數字大小(預設都是首位),誰小誰就歸併到輔助陣列內,然後派出下一個陣列繼續比較(類似車輪戰),最後總有一個序列先把數字“派出來”完了,然後沒有被派出來完的陣列直接把剩餘陣列追加到輔助陣列後面就行了!(注意歸併的時候,兩個序列已經是分別有序的了)
  歸併排序plus(非遞迴模式):上述遞迴實現拆分歸併比較難理解,而且會佔用較大的空間(空間複雜度是nlogn)!,所以建議使用非遞迴的方式來進行拆分和歸併!這個很好理解,首先選取1,2位比較然後歸併;3,4位比較,然後歸併……..,一輪下來將會出現兩兩有序(奇數會剩餘一個);在進行第二輪的兩兩歸併,將會出現四四有序,最後四四歸併,出現八八有序……..直到最後全部有序!(PS:非遞迴方式空間複雜度只有n,時間效能也有提升,所以效能更優,請優先使用!)

7、快速排序:樞軸值——起始時選擇首位數字記錄開始比較,然後從兩邊向中間遍歷,比它大的通過交換放在右邊,比它小的通過交換放在左邊(每次交換後,才把比較的“焦點”從一邊轉向另一邊,即兩邊向中間遍歷。所以並不是第一次比較左邊,第二次就比較右邊了,而是發生交換後才從左邊移向右邊),最後首位數字記錄值的索引號將發生改變這個索引號就是樞軸值;然後對低字表再次遞迴求樞軸值,對高字表再次遞迴求樞軸值(PS:很有前幾天二叉樹推導演算法的遞迴思想)
  快速排序plus:三數取中——對首位、中間位、高位求樞軸值,最後確定變換後的首位數字記錄為整個序列的樞軸值;樞軸值——把當前樞軸值的數字記錄備份到i=0位,由原來的交換改為替換,當遍歷的時候發現替換的兩個數字記錄相等,則當前位置就是實際的樞軸值;然後排序

注:以上為排序演算法的原理性描述,期間涉及遞迴、迴圈等,尤其是索引號的確認(+1或者-1什麼的)以及跳出的條件需要實際程式設計除錯。