逻辑之美(2)_选择排序

开篇

上篇咱们好好聊了聊冒泡排序,这篇咱们来聊聊另外一种初级排序算法——选择排序java

正文

选择排序的算法思路一样很简单。仍是数组为例,咱们如今有个整数数组,要求将其中整数元素按值的大小从小到大排个序。选择排序的具体思路是这样:先从头遍历数组,找出其中值最小的那个元素,而后将其值同遍历区间最开始那个元素交换,若是值最小的元素恰是最开始那个元素,就本身跟本身交换值。第一遍遍历完成,数组中最小的值已是数组第一个元素,此时数组第一个元素已部分有序,将从新遍历的初始下标加一,开始下次遍历,如此循环,直至遍历区间内只剩一个元素,此时数组已总体有序。算法

来具象化捋一遍选择排序的逻辑:数组

``函数

设现有无序数组 a = [40, 50, 20, 30, 10]
    其有序状态应为 a = [10, 20, 30, 40, 50]
    咱们对其作下选择排序,具象展现以下:
数组下标:a[0]  a[1]  a[2]  a[3]  a[4]
初始值: 40   50   20    30   10  

第一次选择遍历过程: 40   50   20   30   10  (遍历区间值最小元素为a[4],
                    ↑                   ↑  与遍历区间初始下标a[0]交换值)
                   
第二次选择遍历过程: 10   50   20   30   40  (最小元素为a[2],与a[1]交换值,
                   ---   ↑    ↑                 下划线标示的元素已部分有序)

第三次选择遍历过程: 10   20   50   30   40  (最小元素为a[3],与a[2]交换值,
                   --------   ↑    ↑          下划线标示的元素已部分有序)
                   
第四次选择遍历过程: 10   20   30   50   40  (最小元素为a[4],与a[3]交换值,
                   ------------    ↑    ↑   下划线标示的元素已部分有序)
                   
第五次选择遍历过程: 10   20   30   40   50  (遍历区间内只剩一个元素了,
                   ------------------  ↑↑   代表此时数组已总体有序)
                   
数组此时已总体有序: 10   20   30   40   50  (数组此时已总体有序)
                   -----------------------
复制代码

OK 逻辑捋的差很少了咱们开始撸代码,以 Java 为例,咱们先来撸个为整数数组选择排序的递归实现版本:post

/** * @see: 选择排序的递归实现 * @param array: 待排序数组,咱们采用原地排序 * @param start: 当次查找最小值(遍历区间)的初始下标,初次调用值应为0 */
    public static void sortSelect(int[] array, int start){
        //递归结束条件,此时数组已总体有序
        if (start >= array.length - 1){
            return;
        }

        //先假定遍历区间第一个下标的值为最小值;
        int minValueIndex = start;
        //开始遍历特定数组区间,将区间内最小值交换到区间初始位置
        for (int i = start + 1; i <= array.length - 1; i ++){
            if (array[i] < array[minValueIndex]){
                minValueIndex = i;
            }
        }
        //把最小的值交换到遍历区间初始下标位置
        int mid = array[start];
        array[start] = array[minValueIndex];
        array[minValueIndex] = mid;
        //递归开始遍历下个遍历区间
        sortSelect(array, start + 1);
    }
复制代码

咱们在实际生产环境中写排序算法确定不能用递归,在 Java 中递归的函数调用栈太深会致开销甚大,上面主要是为便于理解来的初级版本,咱们来优化成非递归版本,即双层嵌套版本:优化

/** * @see: 选择排序的非递归实现,即双层嵌套实现 * @param array: 待排序数组,咱们采用原地排序 */
    public static void sortSelect(int[] array){
        //递归结束条件,此时数组已总体有序
        for (int start = 0; start < array.length - 1; start ++){
            //先假定遍历区间第一个下标的值为最小值;
            int minValueIndex = start;
            for (int startInner = start + 1; startInner <= array.length - 1; startInner ++ ){
                if (array[startInner] < array[minValueIndex]){
                    minValueIndex = startInner;
                }
            }
            //把最小的值交换到遍历区间初始下标位置
            int mid = array[start];
            array[start] = array[minValueIndex];
            array[minValueIndex] = mid;
            //循环开始遍历下个遍历区间
        }
    }
复制代码

两种实现代码撸下来,相信你已完全掌握了选择排序算法。spa

尾巴

选择排序有两个特色:code

  1. 运行时间和输入无关,其时间复杂度恒为 О(n²),即便你输入的数组原本就总体有序也是如此!
  2. 数据值交换(或言数据移动)是最少的,如上所示,一次遍历只有一次值交换,还有多是本身跟本身交换,对比冒泡排序,你知道我在说什么!

选择排序须要的额外空间复杂度同冒泡排序,为О(1)排序

读者请自行发散思惟把以上代码改为为 Comparable 数组排序的版本。递归

下篇咱们聊插入排序。

完。