八大排序算法之2选择排序算法和其优化

选择排序的思路

给定一个数组,总长度为n,按照:

  1. 先假设数组中第一个数据最小
  2. 依次和后面n-1个数相比较,当找到最小的数之后,记录下最小的数min和最小的数的下标
  3. 将第一个假设的数和记录下的最小的数相互交换位置(也就是说在一次循环中最多只交换一次!!
  4. 在假设数组中第二个数是最小的,依次和后面n-2个数相比较,找到并标记下比第二个数还要小的下标和数
  5. 将这两个数相互交换位置。
  6. 依次类推

最粗暴的选择排序代码实现

package com.njupt.Algorithm.select;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/07/18/11:18
 * @Description:
 */
//选择排序的思路

import java.util.Arrays;

/**
 * 1,向假设第一个数就是最小的
 * 2,依次和后面n-1个数进行比较,如果找到最小的,就把第一个假设的位置和这个最小的位置交换
 * 3,再假设第二个数为最小的,以此类推
 */
public class Select {
    public static void main(String[] args) {
        int[] arr = {20, 40, 10, 30};
        System.out.println("原始数据:");
        System.out.print(Arrays.toString(arr) + " ");
        System.out.println(" ");

        //第一次比较,先假设最小的数是下标为0的数
        int minIndex = 0;
        int min = arr[0];
        //开始用第一个数和后面的数组进行比较,故应该从第二个开始,到最后一个
        for (int j = 1; j < arr.length; j++) {
            if (arr[j] < min) {
                //如果第j个数是最小的,先记录下最小的值和下标
                min = arr[j];
                minIndex = j;
            }
        }
        //然后和假设的最小的值进行交换!
        arr[minIndex] = arr[0];
        arr[0] = min;
        //如果最小值的下标发生了变化,则才开始换,如果没有变化说明此次顺序不需要变
            /*if(minIndex!=0){
            }*/
        System.out.println("第一次排序");
        System.out.print(Arrays.toString(arr) + " ");
        System.out.println(" ");

        //第二轮比较之后,应该把第二个作为最小值
        minIndex = 1;
        min = arr[1];
        //开始用第2个数和后面的数组进行比较,故应该从第3个开始比,到最后一个
        for (int j = 2; j < arr.length; j++) {
            if (arr[j] < min) {
                //如果第j个数是最小的,先记录下最小的值和下标
                min = arr[j];
                minIndex = j;
            }
        }
        //然后和假设的最小的值进行交换!
        arr[minIndex] = arr[1];
        arr[1] = min;
        //如果最小值的下标发生了变化,则才开始换,如果没有变化说明此次顺序不需要变
            /*if(minIndex!=0){
            }*/
        System.out.println("第2次排序");
        System.out.print(Arrays.toString(arr) + " ");
        System.out.println(" ");

        //第3轮比较之后,应该把第3个作为最小值
        minIndex = 2;
        min = arr[2];
        //开始用第3个数和后面的数组进行比较,故应该从第4个开始比,到最后一个
        for (int j = 3; j < arr.length; j++) {
            if (arr[j] < min) {
                //如果第j个数是最小的,先记录下最小的值和下标
                min = arr[j];
                minIndex = j;
            }
        }
        //然后和假设的最小的值进行交换!
        arr[minIndex] = arr[2];
        arr[2] = min;
        //如果最小值的下标发生了变化,则才开始换,如果没有变化说明此次顺序不需要变
            /*if(minIndex!=0){
            }*/
        System.out.println("第3次排序");
        System.out.print(Arrays.toString(arr) + " ");
        System.out.println(" ");

    }

}

结果:

原始数据:
[20, 40, 10, 30]  
第一次排序
[10, 40, 20, 30]2次排序
[10, 20, 40, 30]3次排序
[10, 20, 30, 40]  

Process finished with exit code 0

真正的选择排序算法实现:

package com.njupt.Algorithm.select;

import java.util.Arrays;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/07/18/11:48
 * @Description:外层循环是需要比较数子的次数,内层循环是比较每一个数字时,找到并记录下最小的数字
 */
public class RealSelect {
    public static void main(String[] args) {
        int[] arr = {20, 40, 10, 30};
        
        System.out.println("原始数据:");
        System.out.println(Arrays.toString(arr));
        //只需要比较length-1次即可
        for (int i = 0; i < arr.length - 1; i++) {
        //假设这个值就是最小的。
            int minIndex = i;
            int min = arr[i];
            //开始用第一个数和后面的数组进行比较,故应该从第二个开始,到最后一个
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < min) {
                    //如果找到了最小值,只是记录下最小的值和所在的下标,并不需要立马交换值!!!!
                    min = arr[j];
                    minIndex = j;
                }
            }
            //当一次比较中找到了最小的值和下标之后,才开始交换,也就是每次找最小值时,只需要交换一次!
            //先把查找出最小值的地方换成假设的最小值
            arr[minIndex] = arr[i];
            //然后再把最小值换到假设最小值的地方
            arr[i] = min;
            //输出
            System.out.println("第" + (i + 1) + "次排序");
            System.out.print(Arrays.toString(arr) + " ");
            System.out.println(" ");
        }
    }
}

结果:

原始数据:
[20, 40, 10, 30]1次排序
[10, 40, 20, 30]2次排序
[10, 20, 40, 30]3次排序
[10, 20, 30, 40]  

Process finished with exit code 0

选择排序算法存在的问题

不能判断出一次排序中需不需要交换位置,最极端的情况下就是如果传入的数组是一个已经从小到大排好顺序的数组,

int[] arr = {1, 2, 3, 4};

则按照最原始的排序算法来说,还是要交换(自身跟自身交换!)

原始数据:
[1, 2, 3, 4]1次排序
[1, 2, 3, 4]2次排序
[1, 2, 3, 4]3次排序
[1, 2, 3, 4]  

下面开始进行优化

选择排序算法的优化

只需要判断出如果你所假设的最小值的下标和查找比较之后的下标是一样的,没有变化,则说明此假设的数据已经是最小的数,故不需要交换数据,进行下一次假设即可。优化代码如下

package com.njupt.Algorithm.select;

import java.util.Arrays;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/07/18/13:03
 * @Description:
 */
public class BetterSelect {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4,6,5};
        System.out.println("原始数组:");
        System.out.println(Arrays.toString(arr)+" ");
        int count=0;
        for (int i = 0; i < arr.length - 1; i++) {
            //就假设最小值是i
            int min = arr[i];
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                //如果找到了最小值,只是记录下最小的值和所在的下标,并不需要立马交换!!!!
                if (arr[j] < min) {
                    min = arr[j];
                    minIndex = j;
                }
            }
            //当最小值的下标没有变化时,是不需要交换的,也就是达到了优化,减少了交换的次数
            if (minIndex != i) {
                count++;
                arr[minIndex] = arr[i];
                arr[i] = min;
                System.out.println("第" + (i + 1) + "次交换后的结果:");
                System.out.println(Arrays.toString(arr));
            } else {
                //如果最小值的下表和假设的最小值的下标一致,则不需要交换。
                System.out.println("第" + (i + 1) + "次不需要交换");
            }
        }
        System.out.println("最终结果为:");
        System.out.println(Arrays.toString(arr));
        System.out.println("交换的次数为:"+count);

    }
}


结果为:

原始数组:
[1, 2, 3, 4, 6, 5]1次不需要交换
第2次不需要交换
第3次不需要交换
第4次不需要交换
第5次交换后的结果:
[1, 2, 3, 4, 5, 6]
最终结果为:
[1, 2, 3, 4, 5, 6]
交换的次数为:1

从而可以减少交换的次数!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值