選擇排序是一種簡單直觀的原地比較排序。它將陣列劃分為「已排序區」(左側)與「未排序區」(右側)。每一輪從未排序區中找出最小(或最大)元素,將其與未排序區的第一個元素交換,從而擴展已排序區邊界。與冒泡排序「相鄰交換」不同,選擇排序每輪最多只交換一次,減少寫入操作。
初始陣列:[2, 1, 5, 4, 9]
| 輪次 | 未排序區最小值 | 交換動作 | 陣列狀態 |
|---|---|---|---|
| 1 | 1 (索引 1) | swap(0,1) | [1, 2, 5, 4, 9] |
| 2 | 2 (索引 1) | 無(已在正確位置) | [1, 2, 5, 4, 9] |
| 3 | 4 (索引 3) | swap(2,3) | [1, 2, 4, 5, 9] |
| 4 | 5 (索引 3) | 無 | [1, 2, 4, 5, 9] |
void selection_sort(int arr[], int len) {
if (!arr || len <= 1) return;
for (int i = 0; i < len - 1; ++i) {
int min_idx = i;
// 在 [i+1, len-1] 尋找最小值索引
for (int j = i + 1; j < len; ++j) {
if (arr[j] < arr[min_idx]) min_idx = j;
}
// 若最小值不在當前位置,交換
if (min_idx != i) {
int tmp = arr[min_idx];
arr[min_idx] = arr[i];
arr[i] = tmp;
}
}
}
void print_array(const int arr[], int len) {
for (int i = 0; i < len; ++i) printf("%d ", arr[i]);
putchar('\n');
}
void test_selection_sort(void) {
int data[] = {2, 1, 5, 4, 9};
int n = sizeof(data) / sizeof(data[0]);
selection_sort(data, n);
print_array(data, n); // 輸出:1 2 4 5 9
}
| 指標 | 數值 | 說明 |
|---|---|---|
| 時間複雜度 | O(n²) | 最好/最壞/平均皆同,雙層迴圈固定比較次數 |
| 空間複雜度 | O(1) | 原地排序,僅需常數額外空間 |
| 穩定性 | 不穩定 | 交換可能改變相等元素相對順序(如 [5a, 5b, 3] → [3, 5b, 5a]) |
| 交換次數 | O(n) | 每輪最多 1 次,遠少於冒泡/插入排序 |
選擇排序雖非高效排序首選,但其「最小交換次數、原地、簡單」的特性使其在特定場景(小規模資料、寫入昂貴、教學示範)仍具價值。理解其「選擇+交換」模板,有助於進一步掌握堆排序、循環選擇排序等進階演算法。