排序算法:插入排序
微信搜索【程序員囧輝】,關(guān)注這個(gè)堅(jiān)持分享技術(shù)干貨的程序員。
前言
上一次,我們介紹了排序算法中“龜速三兄弟”的大哥“冒泡排序”。今天,我們繼續(xù)介紹“龜速三兄弟”中的二哥——“插入排序”。“冒泡排序”的過(guò)程和代碼相信大多數(shù)人都比較熟悉,但是“插入排序”就不見(jiàn)得了。由于同樣是“龜速三兄弟”中的一員,但是處理過(guò)程沒(méi)有“冒泡排序”那么簡(jiǎn)單明了,因此有不少人可能都沒(méi)接觸過(guò)“插入排序”,本文將通過(guò)例子來(lái)介紹“插入排序”的完整過(guò)程。
?
基本思想
將一個(gè)數(shù)插入一個(gè)已經(jīng)排好序的數(shù)據(jù)中。
?
例子
下面通過(guò)一個(gè)例子來(lái)看看插入排序是怎么工作的。原數(shù)組如下。
第一次循環(huán):
1.從第2個(gè)數(shù)開(kāi)始處理,即array[1]。比較array[1]和arary[0],即15和19。因?yàn)?5 < 19,所以將arary[1]放在array[0]的前面,放完后的數(shù)組如下。
由于是從第2個(gè)數(shù)開(kāi)始處理,一直處理到最后一個(gè)數(shù)。因此,最外層的循環(huán)可以寫(xiě)成如下:
for (int i = 1; i < array.length; i++)至此,第一次循環(huán)結(jié)束。
?
第二次循環(huán):
1.處理第3個(gè)數(shù),即array[2]。首先比較array[2]和array[1],即37和19。因?yàn)?7 > 19,并且前面2個(gè)數(shù)經(jīng)過(guò)第一次循環(huán)后是有序的。因此,直接將37放在array[1]后面的1個(gè)位置即array[2]原位置,放完后的數(shù)組如下。
至此,第二次循環(huán)結(jié)束。
?
第三次循環(huán):
1.處理第4個(gè)數(shù),即array[3]。首先比較array[3]和array[2],即12和37。因?yàn)?2 < 37,所以37此時(shí)在前4個(gè)數(shù)中可以確定是最大的。因此此時(shí)array[3]是37的正確位置,但是array[3]此時(shí)被12占著,所以我們需要用一個(gè)臨時(shí)變量temp存儲(chǔ)arary[3]的值,然后將37填入array[3],填完后的數(shù)組如下。
結(jié)合比較語(yǔ)句,此時(shí)的代碼可以寫(xiě)成如下,在當(dāng)前循環(huán) i = 3。
if (array[i] < array[i - 1]) {// 臨時(shí)變量存儲(chǔ)array[i]的值int temp = array[i]; // array[i - 1]填入此時(shí)屬于它的位置array[i] = array[i - 1]; }?
填充完array[3]后,我們需要將下標(biāo)向前移動(dòng)一個(gè)位置,好將temp(原來(lái)的array[3])跟array[1]進(jìn)行比較,但是此時(shí)下標(biāo) i 代表著循環(huán)的位置不能移動(dòng)。因此,我們需要再定義一個(gè)變量 j 來(lái)記錄比較的位置,因此將上述代碼優(yōu)化成如下:
// 當(dāng)array[i]比arra[i - 1]小時(shí)才進(jìn)入處理 if (array[i] < array[i - 1]) {// 臨時(shí)變量存儲(chǔ)array[i]的值int temp = array[i]; // 定義變量j記錄比較的位置int j = i; // 將比temp大的數(shù)往后挪一個(gè)位置,為temp騰出一個(gè)合適位置while (j > 0 && temp < array[j - 1]) { array[j] = array[j - 1]; j--; // 填充完后, 繼續(xù)向前比較 } }?
2.此時(shí) j 移動(dòng)到下標(biāo)2,比較temp和array[1],即12和19。因?yàn)?2 < 19,并且原來(lái)array[2]位置的數(shù)37此時(shí)已經(jīng)填入array[3],因此此時(shí)array[2]相當(dāng)于一個(gè)坑,直接將19填入即可。將19填入array[2]時(shí),array[1]又形成了一個(gè)新的坑,此時(shí)的數(shù)組如下。
填完后,將下標(biāo) j 繼續(xù)向前移動(dòng)一個(gè)位置。
?
3.此時(shí) j 移動(dòng)到下標(biāo)1,此時(shí)比較temp和array[0],即12和15。因?yàn)?2 < 15,并且原來(lái)array[1]位置的數(shù)19此時(shí)已經(jīng)填入array[2],因此直接將15填入array[1],此時(shí)array[0]又形成了一個(gè)新的坑,此時(shí)的數(shù)組如下。
4.此時(shí) j 移動(dòng)到下標(biāo)0,已經(jīng)沒(méi)有前面的數(shù)可以比較了。因此,array[0]即為temp的位置,將temp填入array[0]后結(jié)束此次循環(huán),此時(shí)的數(shù)組如下。
結(jié)合上面的代碼,將temp填入對(duì)應(yīng)位置的代碼也加上后,代碼如下:
// 當(dāng)array[i]比arra[i - 1]小時(shí)才進(jìn)入處理 if (array[i] < array[i - 1]) {// 臨時(shí)變量存儲(chǔ)array[i]的值int temp = array[i]; // 從當(dāng)前位置開(kāi)始處理int j = i; // 將比temp大的數(shù)往后挪一個(gè)位置,為temp騰出一個(gè)合適位置while (j > 0 && temp < array[j - 1]) { array[j] = array[j - 1]; j--; // 填充完后, 繼續(xù)向前比較 } // 將temp放在屬于它的位置上array[j] = temp; }?
第四次循環(huán)
1.處理第5個(gè)數(shù),即array[4]。首先比較array[4]和array[3],即25和37。因?yàn)?5 < 37,所以將25賦值給temp,并將37填入array[4]的位置,并將下標(biāo) j 向前移動(dòng)一個(gè)位置,此時(shí)的數(shù)組如下。
2.此時(shí) j 移動(dòng)到下標(biāo)3,此時(shí)比較temp和array[2],即25和19。因?yàn)?5 > 19,所以array[3]即為25的位置,將25填入array[3]后結(jié)束此次循環(huán)。
至此,整個(gè)排序過(guò)程結(jié)束。
?
完整過(guò)程
最后我們通過(guò)以下動(dòng)圖來(lái)看插入排序的整個(gè)過(guò)程,圖中紅色的柱子為當(dāng)前要插入的數(shù),橘黃色的柱子為當(dāng)前已經(jīng)排好序的數(shù)據(jù),綠色的柱子為正在跟紅色的柱子比較的數(shù),淺藍(lán)色的柱子為還未插入的數(shù)。
?
整合
上文的例子中已經(jīng)基本將邏輯代碼都寫(xiě)清了,我們將外層循環(huán)和里面的處理邏輯代碼結(jié)合到一起,代碼如下。
public class InsertSort {public static void insertSort(int array[]) {if (array == null || array.length == 0) {return;}for (int i = 1; i < array.length; i++) {// 當(dāng)array[i]比arra[i - 1]小時(shí)才進(jìn)入處理if (array[i] < array[i - 1]) {// 臨時(shí)變量存儲(chǔ)array[i]的值int temp = array[i];// 從當(dāng)前位置開(kāi)始處理int j = i;// 將比temp大的數(shù)往后挪一個(gè)位置,為temp騰出一個(gè)合適位置while (j > 0 && temp < array[j - 1]) {array[j] = array[j - 1];j--; // 填充完后, 繼續(xù)向前比較}// 將temp放在屬于它的位置上array[j] = temp;}}} }?
時(shí)間復(fù)雜度
在最壞的情況下,即整個(gè)數(shù)組是倒序的,比較次數(shù) = 1 + 2 + 3 + ... + (n - 2) + (n - 1) = n * (n - 1) / 2,此時(shí)的時(shí)間復(fù)雜度為:O(n^2)。
在最好的情況下,即整個(gè)數(shù)組是正序的,比較次數(shù) = n - 1,此時(shí)的時(shí)間復(fù)雜度為:O(n)。
?
使用場(chǎng)景
插入排序和冒泡排序一樣。在進(jìn)行量比較大的排序時(shí),最好不要使用。在1000個(gè)數(shù)字以內(nèi)的排序,用插入排序是可以接受的。1000個(gè)隨機(jī)數(shù)使用插入排序耗時(shí)一般在5毫秒以內(nèi),但是當(dāng)數(shù)字個(gè)數(shù)達(dá)到10000個(gè)時(shí),耗時(shí)會(huì)達(dá)到30+毫秒,有比較明顯的耗時(shí),需要慎重使用。
?
相關(guān)閱讀
排序算法:冒泡排序
?
總結(jié)
- 上一篇: 用自己的雷达进行Cartographer
- 下一篇: 国内网页无法加载reCAPTCHA解决方