摘要
選擇排序的邏輯是先遍歷比較出序列中最大的,然後把最大的放在最後位置。
遵循這個邏輯,用程式碼實現時,做到1.減少比較次數之外,這裡引入一個新的指標 - 穩定性,2.保證排序過程中的穩定性也是一個優化處理
程式碼邏輯
- 從頭遍歷序列,分別和尾部元素比較,記錄最大的元素座標
- 遍歷完成後,和尾部位置交換位置
- 忽略尾部已經交換的元素,執行 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)
- 屬於穩定排序