手寫演算法並記住它:選擇排序

老姚發表於2019-09-04

對於經典演算法,你是否也遇到這樣的情形:學時覺得很清楚,可過陣子就忘了?

本系列文章就嘗試解決這個問題。

研讀那些排序演算法,細品它們的名字,其實都很貼切。

比如選擇排序,所謂“選擇”,就是每次遍歷時,選擇一個最小的交換到已排好序列的後面。

手寫演算法並記住它:選擇排序

上圖演示了第三次遍歷,此時元素1和2已經排好序,再在剩下的元素中找到最小的元素3,然後與目標位置交換。

可以看出該演算法的核心是:如何在未排好序的元素中找到最小的元素?

這一點難不倒我們,熊瞎子劈苞米,搞個變數記錄最小下標。

let array = [1, 2, 4, 5, 3]
let minIndex = 2
for (let i = 2; i < array.length; i++) {
  if (array[minIndex] > array[i]) {
    minIndex = i
  }
}
console.log(minIndex) // 4
複製程式碼

找到了最小元素,然後再與目標位置的資料進行交換即可(如果恰好正在目標位置就不用交換了):

if (minIndex !== 2) {
  swap(array, 2, minIndex)
}
console.log(array) // [1, 2, 3, 5, 4]
複製程式碼

其中swap函式封裝了兩個元素如何交換:

function swap(array, i, j) {
  [array[i], array[j]] = [array[j], array[i]]
}
複製程式碼

每次遍歷都排好一個最小的,n次遍歷就能排好所有,可以輕鬆寫出程式碼:

let array = [4, 5, 3, 2, 1]
for (let j = 0; j < array.length; j++) {
  let minIndex = j
  for (let i = j; i < array.length; i++) {
    if (array[minIndex] > array[i]) {
      minIndex = i
    }
  }
  if (minIndex !== j) {
    utils.swap(array, j, minIndex)
  }
}
複製程式碼

完整流程示意如下:

手寫演算法並記住它:選擇排序

上述程式碼,還有優化的空間,比如只需要遍歷n-1次就行了,因為最後一次,必然剩下了一個元素,不需要再做處理。檢視完整程式碼:codepen

至此,選擇排序原理和實現已經說完了。

這裡總結一下,選擇排序不需要額外空間,是本地排序,相等元素是不會交換前後順序,因而也是穩定排序,時間複雜度為O(n^2),適用於少量資料排序,但實際中用得不多。

選擇排序,要做到能分分鐘手寫出來,是需要掌握其排序原理的。每次遍歷核心是找到最小元素然後與目標位置交換即可,一旦內層遍歷能寫出來,那麼整體就很容易寫出來,不需要死記硬背的。

希望有所幫助,本文完。



本系列已經發表文章:

《手寫演算法並記住它:氣泡排序》

相關文章