摘要

選擇排序的邏輯是先遍歷比較出序列中最大的,然後把最大的放在最後位置。

遵循這個邏輯,用程式碼實現時,做到1.減少比較次數之外,這裡引入一個新的指標 - 穩定性,2.保證排序過程中的穩定性也是一個優化處理

程式碼邏輯

  1. 從頭遍歷序列,分別和尾部元素比較,記錄最大的元素座標
  2. 遍歷完成後,和尾部位置交換位置
  3. 忽略尾部已經交換的元素,執行 1 和 2 步驟

實現

依據邏輯來看,最大值是放在尾部,並放置後,下次迴圈排除這個放置最大值的位置,for 迴圈從尾部開始最合適。

小迴圈開始前,需要先建立變數記錄最大值座標,這裡使用的是 0 位置座標,那麼小迴圈開始時,就可以直接從 1 位置遍歷,這就減少比較次數

	for (int end = array.length-1; end > 0; end--) {
int maxIndex = 0;
for (int begin = 1; begin <= end; begin++) {
if (cmp(maxIndex, begin) < 0) {
maxIndex = begin;
}
}
swap(maxIndex, end);
}

進階

開始前,先解釋一下穩定性,穩定性是儘量保持序列中兩個元素在排序前和排序後的相對位置。比如下面虛擬碼:


// a1 與 a2 的值相等
a1 = a2 = 3 // 序列中 a1 值的位置在 a2 前面
array = [5, a1, 4, a2, 2] // 排序之後, a1 值位置在 a2 前面,保持了穩定性
array = [2, a1, a2, 4, 5]

為什麼穩定性重要?

序列中需要保證多次排序後資料位置的相對穩定。比如資訊表中,以 age 從小到大排序,不希望 age 相等的一組資料中,它的名稱在每一次排序之後都會有不同的順序。

穩定性的優化

這裡為了保證排序之後的穩定性,就當出現最大值時,也更新最大值的座標。

為什麼這樣就可以保證穩定性?

首先最大值被交換到尾部之後,下次遍歷比較的時候,就不再比較這個位置,小迴圈的比較是從頭開始的,如果出現等於最大值時,不更新最大值的位置,排序之後,相等的值,最靠前的值就被放在了最後面,改變了之前序列中相等值的相對位置。

	for (int end = array.length-1; end > 0; end--) {
int maxIndex = 0;
for (int begin = 1; begin <= end; begin++) {
if (cmp(maxIndex, begin) <= 0) { // 保證穩定性
maxIndex = begin;
}
}
swap(maxIndex, end);
}

時間和空間複雜度

  • 最好、平均、最壞時間複雜度:O(n^2),n 的 2 次方
  • 空間複雜度:O(1)
  • 屬於穩定排序