演算法導論學習之插入排序
《演算法導論》買了好久了,基本上沒怎麼看,最近思想上有了轉變,覺得學習才是王道。準備重新拾起來學習,下面我就《演算法導論》中的排序演算法中的
插入排序做了個c++的簡單實現,附加解釋一下自己對下面的這段程式碼的理解。
#include "iostream" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { int array[10] = {5,6,1,9,0,3,4,8,2,7}; // 1 for (int i = 1; i < sizeof(array)/sizeof(int); i++) { // 2 int key = array[i]; // 3 int j = i-1; // 4 while (j >= 0 && array[j] > key) { // 5 cout << array[j] << " " << key << endl; // 6 array[j+1] = array[j]; // 7 j--; // 8 } array[j+1] = key; // 9 } return 0; }
插入排序就好像我們玩兒撲克牌一樣,我們左手握著撲克牌,右手一張一張的接牌,左手中的牌總是有順序的。
比如左手中的牌是:紅桃2,紅桃5,紅桃6,這時右手中揭上來了一張紅桃3,我們會整理左手中的牌,把紅桃3插入到紅桃2與紅桃5之間,現在左手中的牌是:紅桃2,紅桃3,紅桃5,紅桃6。
這時,右手又揭上來一張紅桃4,我們再次調整左手中的牌,把紅桃4插入到紅桃3與紅桃5之間,調整後左手中的撲克牌是:紅桃2,紅桃3,紅桃4,紅桃5,紅桃6。
插入排序有3個特點:
1、插入元素前,原來的序列是有序的。
2、每次只插入一個元素。
3、插入元素後,原來的序列的長度增加了1,但仍然是有序的。
下面我將圖文並茂的展示插入排序(升序排序)的執行過程。
假如,我們有10個元素的序列需要排序,序列如下圖:
如下圖中的紅色箭頭將序列分為左、右兩部分:左邊只有一個元素是4
紅色箭頭左邊的4相當於是我們左手中的撲克牌,紅色箭頭右邊的相當於是一堆撲克牌,我們每次從這堆撲克牌中翻最上邊的一張牌。
左邊的序列中只有一個元素4,所以是有順序的。右邊的序列,就像一堆撲克牌一樣,扣在下面只有我們翻開起最上邊的一張牌時,我們才能看到,這張牌到底是什麼,其它牌是什麼,我們根本看不到(所以我們後面的元素都打碼了)。下面我們抽取右邊的第一個元素,插入到左邊的序列中。我們首先把右邊的第一個元素儲存起來,做個備份,要不然一會兒在移動的過程中,會把這個元素給沖掉。如圖:
這時候,我們會把2與左邊的序列從右向左進行比較,由於2<4,所以把4向右移動一個位置。如圖:
所以,明白了,我剛才為什麼要把2(右邊序列的第一個元素)先做個備份吧,最後我們再把2存放到第1個位置。如圖:
現在左邊的序列是2,4是有序的,紅色指標向右移動一位,黑色指標指向紅色指標左邊的第一位,下面我們再取右邊序列的第一個元素,如下圖:
我們首先拿1與左邊序列從右向左第一個元素即4進行比較,1<4,把4向右移動,同時,黑色指標向左移動一位,如圖:
接下來,再讓1與2比較,1<2,把2向右移動一位,黑色指標向左移動一位,如圖:
由於,黑色指標已經指向了序列外,在左邊的序列中,已經沒有比1更小的元素,所以,1應該排在黑色指標右邊的位置,如圖:
現在,左邊的序列已經是有序的,紅色指標再向右移動一位,黑色指標指向紅色指標左邊的第一位。下面取出紅色指標指向的元素,如下圖:
我們比較紅色指標指向的元素,與黑色指標指向的元素,6>4,由於左邊的序列是有序的,而且是從小到大排序的,所以左邊再沒有元素比6大,所以6就應該插入到黑色指標右邊的位置(看起來沒有變化,相當於是6=6,把6賦值給6),如圖:
通過上面的圖片演示,估計大家對插入排序有了較清晰的認識。
紅色指標相當於是外層迴圈中的 i ,黑色指標相當於是內層 while 迴圈中的 j 。只要控制好外層迴圈與內層迴圈,插入排序還是容易寫得出來的,不需要死記硬背。
外層迴圈控制著待插入的元素,內層迴圈控制,左邊有序的序列,一次與待插入的元素進行比較。當左邊的元素比待插入的元素大時,左邊的元素,挨個向右移動。
程式碼很簡短,主要是由兩重迴圈構成的,外迴圈主要是控制迴圈的趟數,如果有n個元素則需要n-1趟外迴圈
int key = array[i];這句是儲存待插入的元素,如果不儲存的話,後面向右移動元素會把待插入的元素沖掉(array[j+1]) = array[j];)
int j = i - 1;則是內迴圈的右邊界,在[0,j]這個區間內與key進行比較,在[0-j]區間內的元素是從小到大有序的。
如果待插入的元素key小於array[j],那麼array[j]應該向右移動,即array[j+1] = array[j],然後待插入的元素key依次再與array[j]左邊的元素做比較,
所以有j--;
內層迴圈結束後表示key<array[j]且key>=array[j-1],所以key應該插入在j的位置上,由於在內層迴圈while中有了j--;所以迴圈結束後key的插入位置為j+1即array[j+1] = key;
參考資料:
《演算法導論》