选择排序法

选择排序法

为什么要学习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。

posted on 2018-07-19 16:29  029简智濠  阅读(194)  评论(0编辑  收藏  举报