选择排序法
为什么要学习O(n^2)的排序算法
- 基础
- 编码简单,是一些简单情景的首选
- 在一些特殊情况下,简单的排序算法更有效
- 简单的排序算法思想衍生出复杂的排序算法
- 作为子过程,改进更复杂的排序算法
选择排序法介绍
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对 {displaystyle n} n个元素的表进行排序总共进行至多 {displaystyle n-1} {displaystyle n-1}次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。
选择排序法动画示例
;
动画中,红色表示当前最小值,黄色表示已排序序列,蓝色表示当前位置
实现代码如下
首先编写通用函数,用于生成指定长度、范围的数组,以及用于测试排序算法的工具函数
const SortTestHelper = () => {
const sth = {
/**
* 生成n个元素的随机数组,范围为 [rangeL,rangeR]
* @param n 指定数组长度
* @param rangeL 随机数组生成范围
* @param rangeR 随机数组生成范围
*/
generateRandomArray: (n, rangeL, rangeR) => {
const newArr = [];
let randomNum;
//生成rangeR->RangeL之间的随机整数
const rangeDiff = rangeR - rangeL + 1;
if (rangeL > rangeR) {
throw new Error('rangeL should less than rangeR');
}
for (let i = 0; i < n; i++) {
randomNum = Math.floor(Math.random() * rangeDiff) + rangeL;
newArr.push(randomNum);
}
return newArr;
},
/**
* 测试数组是否有序
* @param {Array} arr 待测试数组
* @param {Number} n 数组长度
*
* @returns {Boolean} 数组是否有序
*/
isSorted: (arr, n) => {
for (let i = 0; i < n - 1; i++) {
if (arr[i] > arr[i + 1]) {
return false;
}
}
return true;
},
/**
* 测试排序算法
* @param {String} sortName 排序类型
* @param {Array} testArr 测试数组
* @param {Number} n 测试数组长度
*/
testSort: (sortName, sortFn, testArr, n) => {
const startTime = Date.now();
sortFn(testArr, n);
const endTime = Date.now();
if (!sth.isSorted(testArr, n)) {
throw new Error('arr is not sorted!');
}
console.log(`sortName:${sortName}. Total time:${endTime - startTime}ms`);
}
}
return sth;
}
选择排序算法核心
/**
* 实现两数交换
* @param {Array} arr 数组
* @param {Number} i 当前索引位置
* @param {Number} minIndex 带交换的索引位置
*/
const swap = (arr, i, minIndex) => {
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
/**
* 选择排序算法
* @param {Array} arr 待排序的数组
* @param {Number} n 数组长度
*/
const selectionSort = (arr, n) => {
for (let i = 0; i < n; i++) {
//寻找[i,n)区间里的最小值
let minIndex = i;
for (let j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
swap(arr, i, minIndex);
}
}
程序主体就十分简单了,只需要一次调用上面的函数声明即可
//程序主体
let n = 100000; //数组长度
const sth = SortTestHelper();
const arr = sth.generateRandomArray(n, 0, n);
selectionSort(a, n);
console.log(arr);
要检测选择排序的性能的话我们可以编写一个工具函数
/**
* 测试排序算法
* @param {String} sortName 排序类型
* @param {Function} sortFn 排序函数实例
* @param {Array} testArr 测试数组
* @param {Number} n 测试数组长度
*/
testSort: (sortName, sortFn, testArr, n) => {
const startTime = Date.now();
sortFn(testArr, n);
const endTime = Date.now();
if (!sth.isSorted(testArr, n)) {
throw new Error('arr is not sorted!');
}
console.log(`sortName:${sortName}. Total time:${endTime - startTime}ms`);
}
运行代码查看console,只排序长度为10000整型无序数组下,耗时200ms。而排序数量在100000,耗时长达15399ms。