哈嘍,我是程序員大鵬。java
前面咱們介紹了冒泡排序和選擇排序,今天咱們來看一下簡單排序中的插入排序。程序員
打過撲克的都知道,在抓牌的時候,咱們不會等抓完全部的牌再用冒泡或者選擇排序再理牌。通常是拿到一張牌就放到手裏,抓到第二張牌的時候,再跟手裏面已經有的牌進行比較,插到合適的位置,而後抓第三張牌,再與手裏面的兩張牌進行比較,而後再把牌插到合適的位置。這種一邊抓牌,一邊理牌的方式,咱們就稱之爲直接插入排序。算法
插入排序是一種從序列左端開始依次對數據進行排序的算法。在排序過程當中,索引左側的數據陸續歸位,而右側留下的就是尚未被排序的數據。數組
插入排序的思路就是從右側的未排序區域內取出一個數據作爲待排序數據,而後將它插入到已排序區域內合適的位置上。一直到未排序清空。動畫
public static void insertSort(int[] arr) { // 默認第一個元素是有序的,因此索引不是從0開始,從1開始 for (int i = 1; i < arr.length; i++) { int temp = arr[i];//待排序元素賦值給臨時變量 int position = i;//記錄當前比較的索引 while (position > 0 && arr[position - 1] > temp) { arr[position] = arr[position - 1]; position--; } arr[position] = temp;//插入到正確的位置 } }
讓咱們來一行一行地分析一下代碼:code
for (int i = 1; i < arr.length; i++) {
在上面代碼是外層循環,在i的左側是已排序數據,起始的i等於1,是默認第0個數據已是排序數據。blog
int temp = arr[i];//待排序元素賦值給臨時變量 int position = i;//記錄當前比較的索引
每一輪開始的時候,position是待排序數據的索引,temp的值就是本輪待排序的數據,第一輪的待排序索引爲1,第二輪是2,第三輪是3,依次類推,一直到最後一輪。排序
while (position > 0 && arr[position - 1] > temp) {
開始內層的循環,若是知足position大於0,而且當前位置的數據與temp比較,若是大於temp數據,則進入到循環裏面。索引
arr[position] = arr[position - 1]; position--;
數據平移一個位置,將position作爲空隙。it
arr[position] = temp;
將待排序的數據temp插入到空隙的位置。
下面咱們應用插入排序對數組[4,2,3,5,1]進行排序,來看每一步的操做。
這一輪實際上是沒有的,咱們默認就是第一個位置的值是有序的。
將索引值爲1的值2暫時移除,保存在臨時變量temp中,此時temp爲2。
第1步:比較索引0的值4與temp中的
第2步:由於4大於2,因此將4右移。
空隙移到了數組最左端,沒有其餘值能夠比較了。
第3步:將temp插回到數組中,結束第一輪。
將索引爲2的值3暫時移除,保存到臨時變量temp中,此時temp爲3。
第4步:比較4與temp
第5步:由於4比3大,因此將4右移
第6步:比較2與temp
第7步:由於2比3小,因此無須2平移,平移結束
第8步:將temp插回到數組的空隙中,結束第二輪。
將索引爲3的值5暫時移除,保存在臨時變量temp中,此時temp的值爲5.
第9步:比較4與temp
第10步:由於4比5小,,因此無須4平移,平移結束
將索引爲4的值1暫時移除,保存在臨時變量temp中,此時temp的值爲1.
第11步:比較5與temp
第12步:由於5比1大,因此將5右移
第13步:比較4與temp
第14步:由於4比1大,因此將4右移
第15步:比較3與temp
第16步:由於3比1大,因此將3右移
第17步:比較2與temp
第18步:由於2比1大,因此將2右移
空隙移到了數組最左端,沒有其餘值能夠比較了。
第19步:將temp的值1插回到數組的空隙中。
到如今爲止,整個數組已經排好序了。
在插入排序中,須要將取出的數據與其左邊的數字進行比較。就跟前面講的步驟一 樣,若是左邊的數字更小,就不須要繼續比較,本輪操做到此結束,天然也不須要交換 數字的位置。
然而,若是取出的數字比左邊已歸位的數字都要小,就必須不停地比較大小,交換數字,直到它到達整個序列的最左邊爲止。具體來講,就是第 k 輪須要比較k-1 次。因 此,在最糟糕的狀況下,第2 輪須要操做1 次,第 3 輪操做2 次……第n 輪操做n-1 次,因此時間複雜度和冒泡排序的同樣,都爲 O(n^2)。
和前面講的排序算法同樣,輸入數據按從大到小的順序排列時就是最糟糕的狀況。