借用《算法導論》裏的例子,就是咱們打牌的時候,每新拿一張牌都會把它按順序插入,這,其實就是插入排序。java
齊姐聲明:雖然咱們用打牌的例子,可是可不能學胡適先生啊。git
對於數組來講怎麼作呢?github
有一個重要的思想,叫作擋板法,就是用擋板把數組分紅兩個區間:算法
那麼排序分三步走:數組
第一步,擋板最初在這裏:學習
第二步,
把 2 插入已排序區間的正確位置,變成:優化
重複這個步驟,把 1 排好:動畫
最後把 0 排好:spa
那代碼也很簡單:.net
public void insertionSort(int[] input) { if (input.length <= 1) { return; } for(int i = 1; i < input.length; i++) { int tmp = input[i]; int j = i - 1; while(j >= 0 && input[j] > tmp) { input[j+1] = input[j]; j --; } input[j+1] = tmp; } }
咱們來分析一下這個算法的時空複雜度。
關於時間複雜度有兩個要點:
是漸近線複雜度,就是說
那麼咱們關心的 worst case 的狀況就是:
若是數組是近乎倒序的,每次插入都要在數組的第一個位置插入,那麼已排序區間內的全部的元素都要日後移動一位,這一步平均是 O(n),那麼重複 n 次就是 O(n^2).
重點是一個峯值的概念,並非累計使用的空間。
這裏是 O(1) 沒什麼好說的。
引入一個概念:sorted in place,也就是原地排序。
原地排序就是指空間複雜度爲 O(1) 的算法,由於沒有佔用額外的空間,就是原地打轉嘛。
其實 in-place 的思想並非只在排序算法裏有,只不過排序算法是一個最廣爲人知的例子罷了。本質上就是一個節省使用空間的思想。
可是對於排序算法,只分析它的時空複雜度是不夠的,還有另一個重要指標:
這個是排序算法的一個重要指標,意思是元素之間的相對順序是否保持了不變。
好比說:{5, 2, 2, 1, 0}
這個數組排序完成後這裏面的兩個 2 的相對順序沒有變,那麼這個排序就是一個穩定排序。
那有同窗可能就想,順序變了又有什麼關係呢?
其實,在實際工做中咱們排序的對象不會只是一個數字,而是一個個的對象 (object),那麼先按照對象的一個性質來排序,再按照另外一個性質來排序,那就不但願原來的那個順序被改變了。好像有點抽象,咱們舉個例子。
好比在股票交易系統裏,有買賣雙方的報價,那是如何匹配的呢?
那麼一搬來講系統會維持一個按時間排序的價格序列,那麼此時只須要用一個具備穩定性的排序算法,再按照價格大小來排序就行了。由於穩定性的排序算法能夠保持大小相同的兩個對象仍維持着原來的時間順序。
那麼插入排序是不是穩定性的排序呢?答案是確定的。由於在咱們插入新元素的時候是從後往前檢查,並非像打牌的時候隨便插一個位置不能保證相對順序。
你們能夠看下下面的動畫 就很是清楚了~
插入排序實際上是有很大的優化空間的,你能夠搜一下「希爾排序」。
在剛開始學習的時候,深度當然重要,但由於廣度不夠,若是學的太深可能會很痛苦,一個知識點就無窮無盡的延展,這並非一個高效的學習方式。
因此若是時間有限,就要作好深度和廣度的平衡:
保持 open minded 的心態,後期就會有質的提升。
若是你喜歡這篇文章,記得給我點贊留言哦~大家的支持和承認,就是我創做的最大動力,咱們下篇文章見!
我是小齊,紐約程序媛,終生學習者,天天晚上 9 點,雲自習室裏不見不散!
更多幹貨文章見個人 Github: https://github.com/xiaoqi6666...