选择排序
概述
选择排序每次从未排序部分选择最小元素,放到已排序部分的末尾。
算法思想
- 在未排序序列中找到最小元素
- 将其放到已排序序列末尾
- 重复直到所有元素排序完成
算法演示
| Text Only |
|---|
| 初始: 5 3 8 4 2
[2] 3 8 4 5 -> 选择最小2,与5交换
[2] [3] 8 4 5 -> 选择最小3,已在位置
[2] [3] [4] 8 5 -> 选择最小4,与8交换
[2] [3] [4] [5] 8 -> 选择最小5,与8交换
|
基本实现
双向选择排序(鸡尾酒选择排序)
同时找到最小值和最大值,减少排序轮数。
| C |
|---|
| void doubleSelectionSort(int arr[], int n) {
int left = 0, right = n - 1;
while (left < right) {
int minIndex = left, maxIndex = left;
for (int i = left; i <= right; i++) {
if (arr[i] < arr[minIndex]) minIndex = i;
if (arr[i] > arr[maxIndex]) maxIndex = i;
}
int temp = arr[left];
arr[left] = arr[minIndex];
arr[minIndex] = temp;
if (maxIndex == left) maxIndex = minIndex;
temp = arr[right];
arr[right] = arr[maxIndex];
arr[maxIndex] = temp;
left++;
right--;
}
}
|
| C++ |
|---|
| template<typename T>
void doubleSelectionSort(std::vector<T>& arr) {
int left = 0, right = arr.size() - 1;
while (left < right) {
int minIndex = left, maxIndex = left;
for (int i = left; i <= right; i++) {
if (arr[i] < arr[minIndex]) minIndex = i;
if (arr[i] > arr[maxIndex]) maxIndex = i;
}
std::swap(arr[left], arr[minIndex]);
if (maxIndex == left) maxIndex = minIndex;
std::swap(arr[right], arr[maxIndex]);
left++;
right--;
}
}
|
| Python |
|---|
| def double_selection_sort(arr):
left, right = 0, len(arr) - 1
while left < right:
min_index, max_index = left, left
for i in range(left, right + 1):
if arr[i] < arr[min_index]:
min_index = i
if arr[i] > arr[max_index]:
max_index = i
arr[left], arr[min_index] = arr[min_index], arr[left]
if max_index == left:
max_index = min_index
arr[right], arr[max_index] = arr[max_index], arr[right]
left += 1
right -= 1
return arr
|
| Java |
|---|
| public static void doubleSelectionSort(int[] arr) {
int left = 0, right = arr.length - 1;
while (left < right) {
int minIndex = left, maxIndex = left;
for (int i = left; i <= right; i++) {
if (arr[i] < arr[minIndex]) minIndex = i;
if (arr[i] > arr[maxIndex]) maxIndex = i;
}
int temp = arr[left];
arr[left] = arr[minIndex];
arr[minIndex] = temp;
if (maxIndex == left) maxIndex = minIndex;
temp = arr[right];
arr[right] = arr[maxIndex];
arr[maxIndex] = temp;
left++;
right--;
}
}
|
| Go |
|---|
| func doubleSelectionSort(arr []int) {
left, right := 0, len(arr)-1
for left < right {
minIndex, maxIndex := left, left
for i := left; i <= right; i++ {
if arr[i] < arr[minIndex] {
minIndex = i
}
if arr[i] > arr[maxIndex] {
maxIndex = i
}
}
arr[left], arr[minIndex] = arr[minIndex], arr[left]
if maxIndex == left {
maxIndex = minIndex
}
arr[right], arr[maxIndex] = arr[maxIndex], arr[right]
left++
right--
}
}
|
| Rust |
|---|
| fn double_selection_sort(arr: &mut [i32]) {
let mut left = 0;
let mut right = arr.len() - 1;
while left < right {
let mut min_index = left;
let mut max_index = left;
for i in left..=right {
if arr[i] < arr[min_index] {
min_index = i;
}
if arr[i] > arr[max_index] {
max_index = i;
}
}
arr.swap(left, min_index);
if max_index == left {
max_index = min_index;
}
arr.swap(right, max_index);
left += 1;
right -= 1;
}
}
|
复杂度分析
| 情况 |
时间复杂度 |
比较次数 |
交换次数 |
| 最好 |
O(n²) |
n(n-1)/2 |
0 |
| 平均 |
O(n²) |
n(n-1)/2 |
n-1 |
| 最坏 |
O(n²) |
n(n-1)/2 |
n-1 |
空间复杂度:O(1)
稳定性
选择排序是**不稳定排序**:
| Text Only |
|---|
| 原序列: 3A 3B 2 1
选择最小1: 1 3B 2 3A
选择最小2: 1 2 3B 3A (3A和3B顺序改变)
|
稳定选择排序
通过移动元素而不是交换来保持稳定性。
适用场景
- 小规模数据:n较小时可接受
- 交换代价高:交换次数最少(最多n-1次)
- 内存写入敏感:减少写入操作
选择排序 vs 插入排序
| 特性 |
选择排序 |
插入排序 |
| 比较次数 |
固定n(n-1)/2 |
依赖输入 |
| 交换次数 |
最多n-1 |
可能n(n-1)/2 |
| 稳定性 |
不稳定 |
稳定 |
| 有序输入 |
仍需完整比较 |
O(n) |
参考资料