插入排序,通常咱們指的是簡單插入排序,也能夠叫直接插入排序。就是說,每次把一個數插到已經排好序的數列裏面造成新的排好序的數列,以此反覆。算法
插入排序屬於插入類排序算法。segmentfault
除了我之外,有些人打撲克時習慣從第二張牌開始,和第一張牌比較,第二張牌若是比第一張牌小那麼插入到第一張牌前面,這樣前兩張牌都排好序了,接着從第三張牌開始,將它插入到已排好序的前兩張牌裏,造成三張排好序的牌,後面第四張牌繼續插入到前面已排好序的三張牌裏,直至排序完。數組
舉個簡單例子,插入排序一個 4 個元素的數列:4 2 9 1
:數據結構
[]表示排好序 第一輪: [4] 2 9 1 拿待排序的第二個數 2,插入到排好序的數列 [4] 與排好序的數列 [4] 比較 第一輪進行中:2 比 4 小,插入到 4 前 第二輪: [2 4] 9 1 拿待排序的第三個數 9,插入到排好序的數列 [2 4] 與排好序的數列 [2 4] 比較 第二輪進行中: 9 比 4 大,不變化 第三輪: [2 4 9] 1 拿待排序的第四個數 1,插入到排好序的數列 [2 4 9] 與排好序的數列 [2 4 9] 比較 第三輪進行中: 1 比 9 小,插入到 9 前 第三輪進行中: 1 比 4 小,插入到 4 前 第三輪進行中: 1 比 2 小,插入到 2 前 結果: [1 2 4 9]
最好狀況下,對一個已經排好序的數列進行插入排序,那麼須要迭代N-1
輪,而且由於每輪第一次比較,待排序的數就比它左邊的數大,那麼這一輪就結束了,不須要再比較了,也不須要交換,這樣時間複雜度爲:O(n)
。併發
最壞狀況下,每一輪比較,待排序的數都比左邊排好序的全部數小,那麼須要交換N-1
次,第一輪須要比較和交換一次,第二輪須要比較和交換兩次,第三輪要三次,第四輪要四次,這樣次數是:1 + 2 + 3 + 4 + ... + N-1
,時間複雜度和冒泡排序、選擇排序同樣,都是:O(n^2)
。數據結構和算法
由於是從右到左,將一個個未排序的數,插入到左邊已排好序的隊列中,因此插入排序,相同的數在排序後順序不會變化,這個排序算法是穩定的。函數
package main import "fmt" func InsertSort(list []int) { n := len(list) // 進行 N-1 輪迭代 for i := 1; i <= n-1; i++ { deal := list[i] // 待排序的數 j := i - 1 // 待排序的數左邊的第一個數的位置 // 若是第一次比較,比左邊的已排好序的第一個數小,那麼進入處理 if deal < list[j] { // 一直往左邊找,比待排序大的數都日後挪,騰空位給待排序插入 for ; j >= 0 && deal < list[j]; j-- { list[j+1] = list[j] // 某數後移,給待排序留空位 } list[j+1] = deal // 結束了,待排序的數插入空位 } } } func main() { list := []int{5} InsertSort(list) fmt.Println(list) list1 := []int{5, 9} InsertSort(list1) fmt.Println(list1) list2 := []int{5, 9, 1, 6, 8, 14, 6, 49, 25, 4, 6, 3} InsertSort(list2) fmt.Println(list2) }
輸出:性能
[5] [5 9] [1 3 4 5 6 6 6 8 9 14 25 49]
數組規模n
較小的大多數狀況下,咱們可使用插入排序,它比冒泡排序,選擇排序都快,甚至比任何的排序算法都快。code
數列中的有序性越高,插入排序的性能越高,由於待排序數組有序性越高,插入排序比較的次數越少。協程
你們都不多使用冒泡、直接選擇,直接插入排序算法,由於在有大量元素的無序數列下,這些算法的效率都很低。
我是陳星星,歡迎閱讀我親自寫的 數據結構和算法(Golang實現),文章首發於 閱讀更友好的GitBook。