zoukankan      html  css  js  c++  java
  • 选择排序法

    选择排序法

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

  • 相关阅读:
    luogu P3834 【模板】可持久化线段树 1(主席树) 查询区间 [l, r] 内的第 k 小/大值
    覆盖的面积 HDU
    Picture POJ
    Atlantis HDU
    Transformation HDU
    Tunnel Warfare HDU
    Agri-Net POJ
    Conscription POJ
    Brush (IV) LightOJ
    Throwing Dice LightOJ
  • 原文地址:https://www.cnblogs.com/jianzhihao/p/9336598.html
Copyright © 2011-2022 走看看