手写选择排序算法
实现选择排序算法,理解其原理和时间复杂度特点
问题
选择排序(Selection Sort)是一种简单直观的排序算法。它的工作原理是:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
需要实现一个选择排序函数,能够对数组进行升序排序。
解答
/**
* 选择排序
* @param {number[]} arr - 待排序的数组
* @return {number[]} - 排序后的数组
*/
function selectionSort(arr) {
// 创建数组副本,避免修改原数组
const result = [...arr];
const len = result.length;
// 外层循环:控制已排序区间的边界
for (let i = 0; i < len - 1; i++) {
// 假设当前位置是最小值的索引
let minIndex = i;
// 内层循环:在未排序区间中找到最小值的索引
for (let j = i + 1; j < len; j++) {
if (result[j] < result[minIndex]) {
minIndex = j;
}
}
// 如果最小值不是当前位置,则交换
if (minIndex !== i) {
[result[i], result[minIndex]] = [result[minIndex], result[i]];
}
}
return result;
}
/**
* 选择排序(降序版本)
* @param {number[]} arr - 待排序的数组
* @return {number[]} - 排序后的数组
*/
function selectionSortDesc(arr) {
const result = [...arr];
const len = result.length;
for (let i = 0; i < len - 1; i++) {
let maxIndex = i;
for (let j = i + 1; j < len; j++) {
if (result[j] > result[maxIndex]) {
maxIndex = j;
}
}
if (maxIndex !== i) {
[result[i], result[maxIndex]] = [result[maxIndex], result[i]];
}
}
return result;
}
使用示例
// 示例1:基本使用
const arr1 = [64, 25, 12, 22, 11];
console.log('原数组:', arr1);
console.log('升序排序:', selectionSort(arr1));
// 输出: [11, 12, 22, 25, 64]
// 示例2:降序排序
const arr2 = [5, 2, 8, 1, 9];
console.log('降序排序:', selectionSortDesc(arr2));
// 输出: [9, 8, 5, 2, 1]
// 示例3:包含重复元素
const arr3 = [3, 1, 4, 1, 5, 9, 2, 6];
console.log('排序结果:', selectionSort(arr3));
// 输出: [1, 1, 2, 3, 4, 5, 6, 9]
// 示例4:已排序数组
const arr4 = [1, 2, 3, 4, 5];
console.log('已排序数组:', selectionSort(arr4));
// 输出: [1, 2, 3, 4, 5]
// 示例5:单个元素
const arr5 = [42];
console.log('单元素数组:', selectionSort(arr5));
// 输出: [42]
// 示例6:空数组
const arr6 = [];
console.log('空数组:', selectionSort(arr6));
// 输出: []
关键点
-
思想:每次从未排序区间中选择最小(或最大)的元素,放到已排序区间的末尾
-
双层循环结构:
- 外层循环控制已排序区间的边界(i 从 0 到 n-2)
- 内层循环在未排序区间中查找最小值(j 从 i+1 到 n-1)
-
原地排序:只需要常数级的额外空间,通过交换元素位置完成排序
-
时间复杂度:
- 最好情况:O(n²)
- 平均情况:O(n²)
- 最坏情况:O(n²)
- 无论数据初始状态如何,都需要进行完整的比较
-
空间复杂度:O(1),只需要一个临时变量用于交换
-
稳定性:选择排序是不稳定的排序算法,因为交换操作可能改变相同元素的相对位置
-
优化技巧:可以同时找出最小值和最大值,分别放到序列两端,减少遍历次数
-
适用场景:数据规模较小、对稳定性无要求的场景;由于交换次数少(最多 n-1 次),在交换操作代价较大时有优势
目录