在這篇文章中,你將看到最容易理解的一種排序方法:直接插入排序。
請保證你有連續的20分鐘來看這個算法,如果你用2分鐘就看明白了,好吧,你一定是超人。
首先來描述下直接插入排序的算法,我們以升序為例。
數據準備:一個無序的整形數組: {5, 8, 2, 7, 11, 20, 9, 1}
算法介紹:
-
當某個數組中只有一個元素的時候,我們認為此數組是有序的。
比如:{5},他只有一個元素,那他就是有序的,ok?
從需要排序的數組的第二個元素開始,我們將對他進行插入排序;
在上面的數組中第二個元素是 8 對吧?
真正的排序馬上開始;
-
我們拿到了 8, 同他前面所有的有序的子數組的每個元素進行比較,
對于我們的例子來講,8 前面的“有序的子數組”就是 {5},
那么 8 會跟 5 去比較。
比較的結果是 8 > 5,則不做任何處理;
8 接下來跟子數組的其他元素比較,我們發現已經比較完了,
那么ok,對 8 這個元素,因為他跟5相比,本身就是升序,所以我們沒有做任何移動;
-
到此,你會不會說我在說廢話?沒關系,好戲馬上開始了。
8 的下一個元素是2。
2 也會跟他前面的“有序的子數組” 進行比較,此時這個子數組是 {5, 8},
所以這次需要跟兩個元素進行比較。
那么先跟誰比呢?答案是先跟 8 比較,具體過程如下,
1) 2 > 8 嗎?不大于,好的,2 和 8 交換位置。
啊?不是吧?你不知道交換位置是怎么回事嗎?那我先說下這個吧:
比如 你有兩個瓶子,一個瓶子裝著醋,一個瓶子裝著醬油,現在你突然發神經,想要把這倆瓶子換換個。
怎么辦呢?好辦,你去找一個你喝過的雪碧的瓶子,你會這么做:
把醋倒到雪碧瓶子,那么醋瓶子就空了;
把醬油倒到醋瓶子,那么醬油瓶子就空了,此時醋瓶子里面裝了醬油哈;
把雪碧瓶子的醋倒到醬油瓶子里,那么雪碧瓶子空了,此時醬油瓶子就裝了醋了。
則交換后數組看起來是這樣:
{5, 2, 8, ...} ,...代表剩下的未經排序的元素,因為暫時還不涉及他們,故省略;
2) 那么接下來,2 和 5 比較,2 > 5 嗎?不大于,同理,2 和 5交換,交換后變成這樣:
{2, 5, 8, ...}
3) 接下來還要比較嗎?不用了,因為{5, 8}這兩個元素已經比較完了。
好的,到此為止,我們看到的數組是這樣的:
{2, 5, 8, 7, 11, 20, 9, 1}
下面的問題就以此類推了,很簡單,我們繼續啰嗦下下一個元素: 7 的排序過程:
7的前面的“有序的子數組”是{2, 5, 8},因此,他需要比較3次。
同理,從后往前做比較,先跟8比:
1) 7 > 8 嗎?不大于,好的交換,則為{2, 5, 7, 8};
2) 7 > 5 嗎?是的,大于,好的,到此,我們可以停下來了;
3) 呃?你是說break嗎?是的,就是break,為什么可以break呢?因為我們知道待比較的子數組是有序的,
所以呢,5前面的數字一定比5小(當然也可能等于,本例中沒有出現這個情況而已,不管怎么樣,他一定是小于等于5的)
那么,我們可以百分百確定,7不會出現在5的前面,所以就不跟前面的數字進行比較了。
我相信,如果你按照上面的自己一步步讀下來,一定可以把最初的數組排序成功。
算法講完了,那么我們來了解下他的時間復雜度是多少呢?
時間復雜度,是O(n^2);這個時間復雜度我說不太清了,大家還是百度或谷歌吧。
空間復雜度,就是O(1)吧,因為我們只用了一個臨時空間。
說到最后還是要用代碼來實現,這是我的Java實現:
static void insertSort(int[] array) {
int tmp = 0;
for (int i = 1; i < array.length; i++) {
tmp = array[i];
for (int j = i - 1; j >= 0; j--) {
if (array[j] > tmp) {
array[j+1] = array[j];
array[j] = tmp;
}
else {
break;
} // End of else
} // End of for (j)
} // End of for (i)
} // End of insertSort(..)
能看懂嗎?
簡單描述下:
第三行的for循環從 1 開始,咦?為什么是 1 呢? 數組下標不是從 0 開始嗎?
對,你說的是對的,數組下標是從 0 開始,但對于我們的算法來講,
從 0 開始,0 號元素前面是沒有任何 “有序的子數組” 的,故我們從 1 開始,
那么 1 號元素前面的“有序的子數組”就是 {0號元素}。
接下來,我們在第四行,把 i 號元素的值保存到 tmp 了;
下面第6行又是一個循環,在這個循環中,我們從 i - 1 開始,比較 i - 1 元素的值與 tmp 之間的關系。
如果要比較的元素 大于 tmp 了,那么就把他們換換位置;
否則呢,就break。
這里break的原因在上面已經講到了。
此講結束,下一講準備是來說說 直接插入排序的改進算法:希爾排序。
不知道你看完并理解整個過程花了多長時間呢?20分鐘夠嗎?如果不夠,原因是什么,是我寫的不夠詳細看不明白?還是我寫的太多了,光讀文字就花了半小時呢 嘿嘿。
Anyway, hope this helps.