上一次,我們介紹了排序演算法中「龜速三兄弟」的大哥「氣泡排序」。今天,我們繼續介紹「龜速三兄弟」中的二哥——「插入排序」。「氣泡排序」的過程和**相信大多數人都比較熟悉,但是「插入排序」就不見得了。由於同樣是「龜速三兄弟」中的一員,但是處理過程沒有「氣泡排序」那麼簡單明瞭,因此有不少人可能都沒接觸過「插入排序」,本文將通過例子來介紹「插入排序」的完整過程。
將乙個數插入乙個已經排好序的資料中。
第一次迴圈時,從第2個數開始處理。我們將第1個數作為已經排好序的資料:當第2個數 > 第1個數時,將第2個數放在第1個數後面乙個位置;否則,將第2個數放在第1個數前面。此時,前兩個數形成了乙個有序的資料。
第二次迴圈時,我們處理第3個數。此時,前兩個數形成了乙個有序的資料:首先比較第3個數和第2個數,當第3個數 > 第2個數時,將第3個數放在第2個數後面乙個位置並結束此次迴圈;否則,再和第1個數比較。如果第3個數 > 第1個數,則將第3個數插入第1個數和第2個數中間;否則,第3個數 < 第1個數,則將第3個數放在第1個數前面。此時,前三個數形成了乙個有序的資料。
後續的資料同理處理,直至結束。
下面通過乙個例子來看看插入排序是怎麼工作的。原陣列如下。
第一次迴圈:
1.從第2個數開始處理,即array[1]。比較array[1]和arary[0],即15和19。因為15 < 19,所以將arary[1]放在array[0]的前面,放完後的陣列如下。
由於是從第2個數開始處理,一直處理到最後乙個數。因此,最外層的迴圈可以寫成如下:
for (int i = 1; i < array.length; i++)
至此,第一次迴圈結束。
第二次迴圈:
1.處理第3個數,即array[2]。首先比較array[2]和array[1],即37和19。因為37 > 19,並且前面2個數經過第一次迴圈後是有序的。因此,直接將37放在array[1]後面的1個位置即array[2]原位置,放完後的陣列如下。
至此,第二次迴圈結束。
第三次迴圈:
1.處理第4個數,即array[3]。首先比較array[3]和array[2],即12和37。因為12 < 37,所以37此時在前4個數中可以確定是最大的。因此此時array[3]是37的正確位置,但是array[3]此時被12佔著,所以我們需要用乙個臨時變數temp儲存arary[3]的值,然後將37填入array[3],填完後的陣列如下。
結合比較語句,此時的**可以寫成如下,在當前迴圈 i = 3。
if (array[i] < array[i - 1])
填充完array[3]後,我們需要將下標向前移動乙個位置,好將temp(原來的array[3])跟array[1]進行比較,但是此時下標 i 代表著迴圈的位置不能移動。因此,我們需要再定義乙個變數 j 來記錄比較的位置,因此將上述**優化成如下:
// 當array[i]比arra[i - 1]小時才進入處理
if (array[i] < array[i - 1])
}
2.此時 j 移動到下標2,比較temp和array[1],即12和19。因為12 < 19,並且原來array[2]位置的數37此時已經填入array[3],因此此時array[2]相當於乙個坑,直接將19填入即可。將19填入array[2]時,array[1]又形成了乙個新的坑,此時的陣列如下。
填完後,將下標 j 繼續向前移動乙個位置。
3.此時 j 移動到下標1,此時比較temp和array[0],即12和15。因為12 < 15,並且原來array[1]位置的數19此時已經填入array[2],因此直接將15填入array[1],此時array[0]又形成了乙個新的坑,此時的陣列如下。
4.此時 j 移動到下標0,已經沒有前面的數可以比較了。因此,array[0]即為temp的位置,將temp填入array[0]後結束此次迴圈,此時的陣列如下。
結合上面的**,將temp填入對應位置的**也加上後,**如下:
// 當array[i]比arra[i - 1]小時才進入處理
if (array[i] < array[i - 1])
// 將temp放在屬於它的位置上
array[j] = temp;
}
第四次迴圈1.處理第5個數,即array[4]。首先比較array[4]和array[3],即25和37。因為25 < 37,所以將25賦值給temp,並將37填入array[4]的位置,並將下標 j 向前移動乙個位置,此時的陣列如下。
2.此時 j 移動到下標3,此時比較temp和array[2],即25和19。因為25 > 19,所以array[3]即為25的位置,將25填入array[3]後結束此次迴圈。
至此,整個排序過程結束。
最後我們通過以下**來看插入排序的整個過程,圖中紅色的柱子為當前要插入的數,橘黃色的柱子為當前已經排好序的資料,綠色的柱子為正在跟紅色的柱子比較的數,淺藍色的柱子為還未插入的數。
上文的例子中已經基本將邏輯**都寫清了,我們將外層迴圈和裡面的處理邏輯**結合到一起,**如下。
public class insertsort
for (int i = 1; i < array.length; i++)
// 將temp放在屬於它的位置上
array[j] = temp;}}
}}
在最壞的情況下,即整個陣列是倒序的,比較次數 = 1 + 2 + 3 + ... + (n - 2) + (n - 1) = n * (n - 1) / 2,此時的時間複雜度為:o(n^2)。
在最好的情況下,即整個陣列是正序的,比較次數 = n - 1,此時的時間複雜度為:o(n)。
插入排序和氣泡排序一樣。在進行量比較大的排序時,最好不要使用。在1000個數字以內的排序,用插入排序是可以接受的。1000個隨機數使用插入排序耗時一般在5毫秒以內,但是當數字個數達到10000個時,耗時會達到30+毫秒,有比較明顯的耗時,需要慎重使用。
排序演算法:氣泡排序
排序演算法 插入排序
插入排序 insertion sort 的演算法描述是一種簡單直觀的排序演算法。它的工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃瞄,找到相應位置並插入。插入排序在實現上,通常採用in place排序 即只需用到o 1 的額外空間的排序 因而在從後向前掃瞄過程中,需要反覆把已排...
排序演算法 插入排序
排序演算法之插入排序 參照新版程式 下面是錯誤的理解,正確的參考,後文已經修改過的部分。選擇排序,顧名思義,就是選擇乙個元素進行排序。原理 將原始序列分成兩部分,一部分已經有序,一部分無序。將無序中的元素逐個插入到有序序列中。這個也是兩層迴圈,就我個人理解,與氣泡排序是乙個原理。氣泡排序是每次都從無...
排序演算法 插入排序
插入排序簡單來說 就是將乙個資料插入到已經到排好的序列中,但要求插入後仍然有序。這種方法一般適用少量資料的。一 主要的插入排序 直接插入排序 二分插入排序 鍊錶插入排序,希爾排序,是屬於穩定排序的一種。二 直接插入排序 把n個待排序的元素看成為乙個有序表和乙個無序表,開始時有序表中只包含乙個元素,無...