對於經典演算法,你是否也遇到這樣的情形:學時覺得很清楚,可過陣子就忘了?
本系列文章就嘗試解決這個問題。
研讀那些排序演算法,細品它們的名字,其實都很貼切。
比如插入排序,所謂“插入”,實指把待排序元素插入到已排好的序列裡。
上圖演示了第4次遍歷,此時元素1、3、5已經是有序序列,待排的元素是2,要把它插入到1和3之間。此時3和5都往後移動了一位。
可以看出該演算法的核心是:如何在有序序列裡找到正確的插入位置?
思路是從有序序列的尾部開始,逐個與目標元素比較,如果大於目標元素,該元素需要後移。
可以看出之所以先要快取一下目標,是為了要把它的位置先空下來,方便其他元素移入。 另外,當元素不大於目標時,此時說明要插入目標的位置已經找到了。
翻譯成程式碼:
let array = [1, 3, 5, 2, 4]
let i = 3
let target = array[3]
while(i > 0 && array[i-1] > target) {
array[i] = array[i-1]
i--
}
array[i] = target
console.log(array) // [ 1, 2, 3, 5, 4 ]
複製程式碼
能插入成功一個,遍歷n-1次(第一個元素本身就是有序序列了),就可以全部插入,程式碼很容易寫出來:
for (let j = 1; j < array.length; j++) {
let i = j
let target = array[i]
while(i > 0 && array[i-1] > target) {
array[i] = array[i-1]
i--
}
array[i] = target
}
複製程式碼
檢視完整程式碼:codepen。
至此,插入排序原理和實現已經說完了。
這裡總結一下,插入排序不需要額外空間,是本地排序,相等元素是不會交換前後順序,因而也是穩定排序,時間複雜度為O(n^2),適用於少量資料排序。相比氣泡排序和選擇排序,插入排序的使用相對多一些。因為前兩者是交換排序,本質上需要3次原子操作的。
插入排序,要做到能分分鐘手寫出來,是需要掌握其排序原理的。每次遍歷核心是找到正確的插入位置,一旦內層遍歷能寫出來,那麼整體就很容易寫出來,不需要死記硬背的。
希望有所幫助,本文完。
本系列已經發表文章: