数据结构与算法之选择排序

一、基本思想

选择排序(select sorting)基本思想是:第一次从arr[0] ~ arr[n-1]中选取最小值,与arr[0]交换;第二次从arr[1] ~ arr[n-1]中选取最小值,与arr[1]交换,第三次从arr[2]~arr[n-1]中选取最小值,与arr[2]交换…第i次从arr[i-1] ~ arr[n-1]中选取最小值,与arr[i-1]交换…,第n-1次从arr[n-2]~arr[n-1]中选取最小值,与arr[n-2]交换,总共通过n-1次,得到一个按排序码从小到大排列的有序序列。

二、例如

主要思想就是假设第一个数据是最小值,然后跟右侧对比,看看谁最小,谁最小就标记谁,然后拿着标记值(最小值)再去和右边找,就这样一直找一直找,最后找到一个在全部数据中的最小值,与第一个数据互换位置,第二次找就从第二个位置开始(因为第一个位置已经是最小值了),以此类推。

原始数据:

[10, 34, 100, 1]

第一次选择排序:

[1,34,100,10]

先假设最小值是第一个数据,也就是10,然后先拿10和34对比大小,10<34,不处理,继续拿10和100比较,10<100,不处理,继续拿10和1比较,10>1,重新记录下最小值是1,发现1右边没数据了,不能对比,所以循环结束,将10和1的位置互换即可。

第二次选择排序:

[1,10,100,34]

这次要从第二个数据开始了,所以先假设最小值是第二个数据34,然后拿34和100对比,34<100,不处理,在拿34和10对比,34>10,重新记录当前最小值为10,发现10右边没数据了,不能对比,所以循环结束,将34和10的位置互换即可。

第三次选择排序:

[1,10,34,100]

这次要从第三个数据开始了,所以先假设最小值是第三个数据100,然后拿100和34对比,100>34,重新记录当前最小值为34,发现34右边没数据了,不能对比,所以循环结束,将100和34的位置互换即可。

三、coding

1、lowb演示版

package com.chentongwei.struct.sort;

import java.util.Arrays;

/**
 * Description:
 * 10, 34, 100, 1
 *
 * @author TongWei.Chen 2019-12-31 11:05:18
 */
public class SelectorSort {
    public static void main(String[] args) {
        int[] arr = {10, 34, 100, 1};
        selectSort(arr);
    }

    public static void selectSort(int[] arr) {
        // 逐步推导的方式讲解选择排序
        // 先假定最小值是下标为0的元素
        int minIndex = 0;
        int minValue = arr[minIndex];
        // 从当前数之后的数比较,所以是0 + 1
        for (int j = 0 + 1; j < arr.length; j++) {
            if (minValue > arr[j]) {
                // 代表假定的最小值并不是最小值,需要重置下minIndex和minValue
                minValue = arr[j];
                minIndex = j;
            }
        }
        // 将最小值放在arr[0]的位置,把arr[0]的值放在最小值的位置,也就是交换一下
        if (minIndex != 0) {
            arr[minIndex] = arr[0];
            arr[0] = minValue;
        }
        System.out.println("第一轮后:");
        System.out.println(Arrays.toString(arr));

        // 先假定最小值是下标为1的元素
        minIndex = 1;
        minValue = arr[minIndex];
        // 从当前数之后的数比较,所以是1 + 1
        for (int j = 1 + 1; j < arr.length; j++) {
            if (minValue > arr[j]) {
                // 代表假定的最小值并不是最小值,需要重置下minIndex和minValue
                minValue = arr[j];
                minIndex = j;
            }
        }
        // 将最小值放在arr[1]的位置,把arr[1]的值放在最小值的位置,也就是交换一下
        if (minIndex != 1) {
            arr[minIndex] = arr[1];
            arr[1] = minValue;
        }
        System.out.println("第二轮后:");
        System.out.println(Arrays.toString(arr));

        // 先假定最小值是下标为1的元素
        minIndex = 2;
        minValue = arr[minIndex];
        // 从当前数之后的数比较,所以是1 + 1
        for (int j = 2 + 1; j < arr.length; j++) {
            if (minValue > arr[j]) {
                // 代表假定的最小值并不是最小值,需要重置下minIndex和minValue
                minValue = arr[j];
                minIndex = j;
            }
        }
        // 将最小值放在arr[2]的位置,把arr[2]的值放在最小值的位置,也就是交换一下
        if (minIndex != 2) {
            arr[minIndex] = arr[2];
            arr[2] = minValue;
        }
        System.out.println("第三轮后:");
        System.out.println(Arrays.toString(arr));
    }
}

第一轮后:
[1, 34, 100, 10]
第二轮后:
[1, 10, 100, 34]
第三轮后:
[1, 10, 34, 100]

代码很low,就是为了演示说明选择排序是怎么回事,可以发现代码几乎相同,只是某个变量不同而已。

2、优化版

package com.chentongwei.struct.sort;

import java.util.Arrays;

/**
 * Description:
 * 10, 34, 100, 1
 *
 * @author TongWei.Chen 2019-12-31 11:05:18
 */
public class SelectorSort {
    public static void main(String[] args) {
        int[] arr = {10, 34, 100, 1};
        selectSortNew(arr);
    }

    public static void selectSortNew(int[] arr) {
        // 原始数组:[101, 34, 119, 1]
        for (int i = 0; i < arr.length - 1; i++) {
            // 先假定最小值是下标为i的元素
            int minIndex = i;
            int minValue = arr[minIndex];
            // 从当前数之后的数比较,所以是i + 1
            for (int j = i + 1; j < arr.length; j++) {
                if (minValue > arr[j]) {
                    // 代表假定的最小值并不是最小值,需要重置下minIndex和minValue
                    minValue = arr[j];
                    minIndex = j;
                }
            }
            // 将最小值放在arr[0]的位置,把arr[0]的值放在最小值的位置,也就是交换一下
            if (minIndex != i) {
                arr[minIndex] = arr[i];
                arr[i] = minValue;
            }
            System.out.println("第"+ (i + 1) +"轮后:");
            System.out.println(Arrays.toString(arr));
        }
    }
}

第1轮后:
[1, 34, 100, 10]
第2轮后:
[1, 10, 100, 34]
第3轮后:
[1, 10, 34, 100]

将上面lowb版进行升级,也就是将变量部分换成了一层for来解决。时间复杂度O(n2)

四、测试效率

测试10w条数据,选择排序需要花费时间。

package com.chentongwei.struct.sort;

import java.util.Arrays;

/**
 * Description:
 * 10, 34, 100, 1
 *
 * @author TongWei.Chen 2019-12-31 11:05:18
 */
public class SelectorSort {
    public static void main(String[] args) {
        // 测试选择排序的效率,假设给10w个数据测试
        int[] arr = new int[100000];
        for (int i = 0; i < arr.length; i ++) {
            // 生成【0,8000000】之间的一个随机数
            arr[i] = (int)(Math.random() * 8000000);
        }
        long startTime = System.currentTimeMillis();
        selectSortNew(arr);
        long endTime = System.currentTimeMillis();
        System.out.println("选择排序10w个数据所需要的时间是:" + (endTime - startTime) / 1000);
    }

    public static void selectSortNew(int[] arr) {
        // 原始数组:[101, 34, 119, 1]
        for (int i = 0; i < arr.length - 1; i++) {
            // 先假定最小值是下标为i的元素
            int minIndex = i;
            int minValue = arr[minIndex];
            // 从当前数之后的数比较,所以是i + 1
            for (int j = i + 1; j < arr.length; j++) {
                if (minValue > arr[j]) {
                    // 代表假定的最小值并不是最小值,需要重置下minIndex和minValue
                    minValue = arr[j];
                    minIndex = j;
                }
            }
            // 将最小值放在arr[0]的位置,把arr[0]的值放在最小值的位置,也就是交换一下
            if (minIndex != i) {
                arr[minIndex] = arr[i];
                arr[i] = minValue;
            }
        }
    }
}

选择排序10w个数据所需要的时间是:6

可以发现只需要6s就能排序完10w条数据,对比上一篇的冒泡来讲简直神速,冒泡10w条需要24s。四倍的提升。具体原因是什么呢?是因为选择排序不需要每次都互换位置,而是内层循环完成后找到了最小值后,外层循环才开始互换位置,而冒泡是每次内层循环都互换一次位置。这里的互换位置并不是简单的赋个值就影响效率了,而是每一次都互换位置必然导致进入双层for循环里的if条件的次数过多。因为每一次都呼唤位置会导致数据每次都发生变化,满足if判断的次数也就会变多。对比冒泡的缺点就是选择不能优化,时间复杂度最好最坏都是O(n2),而冒泡可以优化到最好时间复杂度为O(n)。

冒泡排序

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【原】编程界的小学生

没有打赏我依然会坚持。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值