什么是算法
在說插入排序之前,我們了解下《算法導論》對算法的從兩種不同角度的定義。
一般性解釋:
算法是定義良好的計算過程,它取一個或一組值作為輸入,并產生出一個或一組值作為輸出。
基于應用的解釋:
算法是一種工具,用來解決一個具有良好規格說明的計算問題。該問題的描述可以用通用的語言,來規定所需的輸入/輸出關系。與之對應的算法則描述了一個特定的計算過程,用于實現這一輸入/輸出關系。
后一種解釋在告訴我們,我們不必對于每個問題都去重新設計、證明和實現算法,而是有能力將實際問題轉換成已知算法問題,然后選取合適的解法。而這種能力就是學習算法的目的所在。這要求我們不僅要積累算法知識,還要在更高的抽象層次上理解算法的方法論。
排序問題的形式定義
排序問題是算法要解決的一個基本問題。它的形式化定義如下:
輸入:n個數的一個序列[a1, a2, ..., an]。
輸出:輸出序列的一個排列[a1', a2', ..., an'], 滿足a1' ≤ a2' ≤ ... ≤ an'。
插入排序算法
插入排序算法,對于少量元素的排序問題,是一個有效的算法。
經典應用
撲克
即便是玩過撲克牌的小孩子,其實都對插入排序算法了然于胸。
- 摸牌之前,所有將會被你摸到的牌,此時是一種亂序的狀態。
- 你開始摸牌,并將新摸到的牌插入到合適的位置,以保證你手中的牌總是有序的。
- 直到摸到最后一張,將其插入到合適的位置,此時你手中所有的牌就已經排好序了。
算法的抽象表達
想讓計算機聽懂上述的算法,需要將其進行翻譯。
INSERTION-SORT(A)
1 for j = 2 to A.length
2 key = A[j]
3 // Insert A[j] into the sorted sequence A[1..j-1].
4 i = j - 1
5 while i > 0 and A[i] > key
6 A[i + 1] = A[i]
7 i = i - 1
8 A[i + 1] = key
原著中的偽碼無可挑剔,就沿用了。做一些說明:
- 算法名稱INSERT-SORT;
- A是一個長度為n的要排序的數組,用A.length表示n;
- 把待排序數組A邏輯上分為兩個數組,排好序的(手中的牌),未排序的(桌上待摸的牌);
- 排好序的數組起始只有一個元素,就是原數組A的第一個元素(摸出的第一張牌無需排序),循環變量用i表示;
- 未排序的數組起始,從原數組A的第二個元素一直到最后一個元素,所以外層的遍歷是“2 to A.length”,循環變量用j表示;
- 外層遍歷過程中,每個當前元素A[j]都暫存至key變量中;
- key要加入排序好的數組,會從該排序好數組的最末i(j-1)開始進行比較,如果A[i]大于key,A[i]移動到A[i+1],i自減,繼續與key比較,如果此時i ≤ 0 或者 A[i] ≤ key,循環條件不成立跳出,將key存入A[i+1]。
算法工作例子
插入算法如何工作
說明:
- (a)~(e)是循環迭代,(f)是最終排好的數組;
- 數組上方是數組的下標;
- 黑色塊表示每次外層迭代,待插入左側數組的數A[j];
- 灰色塊表示參與和A[j]比較的數;
- 黃色箭頭是偽碼第6行表達的移動;
- 藍色大箭頭是偽碼第8行表達的移動;
Java實現
public class InsertionSort {
public static void sortInASC(int[] numbers){
for(int j = 1; j < numbers.length; j++){
int key = numbers[j];
int i = j - 1;
while(i >= 0 && numbers[i] > key){
numbers[i + 1] = numbers[i];
i = i - 1;
}
numbers[i + 1] = key;
}
}
}
共享協議:署名-非商業性使用-禁止演繹(CC BY-NC-ND 3.0 CN)
轉載請注明:作者黑猿大叔(簡書)