选择排序学习

本文详细介绍了选择排序的工作原理,对比了它与冒泡排序的区别,并提供了优化过的选择排序算法实现。通过示例代码展示了如何找到数组中的第K个最大元素以及对整个数组进行排序。同时,讨论了选择排序的不稳定性及其在某些情况下的效率问题。
摘要由CSDN通过智能技术生成

概念

​ 前面学习了冒泡排序,其实我一直将冒泡和选择搞混淆,因为冒泡也是每次循环找到最大或者最小的元素,但是冒泡多了一步交换。选择排序就不同,每次循环找到最大值或者最小值,最后才将其放到队尾或者队首。

​ 说这这里,选择排序的概念就很清楚了,有两个循环,外循环遍历所有的元素,内循环遍历找到最大值,内循环完成后,将当前循环的最大值移动到队尾。外循环完成后,排序也就完成了。示意图如下:

img

代码

​ 代码来说就比较简单了,甚至比冒泡排序还要简单。如下:

public static void selectionSort(int[] arr) {
    int length = arr.length;
    int minIndex = 0;
    //循环到数组到前一个元素即可。
    for (int i = 0; i < length - 1; i++) {
        minIndex = i;
        for (int j = i + 1; j < length; j++) {
            if (arr[j] < arr[minIndex]) minIndex = j;
        }
        BaseSort.swap(arr, i, minIndex);
    }
}

​ 看代码也能看出来,选择排序对于数组中元素的位置有破坏,即大家常说的选择排序不稳定。(如果数组中两个元素的位置经过排序后发生了变化,这种算法就是不稳定的)冒泡排序因为每次比较都可能交换了位置,所以冒泡排序后的数组元素的位置仍然能够保持之前的位置。(相同的元素)这也是选择排序的一个缺点吧。

优化

​ 选择排序的优化思路也比较好想,就是在比较多过程中同时找到最大值和最小值。这样会比原有的写法快一点。代码如下:

public static void selectionSort2(int[] arr) {
    int length = arr.length;
    int minIndex, maxIndex;
    for (int i = 0; i < length; i++) {
        minIndex = maxIndex = i;
        for (int j = i + 1; j < length - i; j++) {
            if (arr[j] < arr[minIndex]) minIndex = j;
            if (arr[j] > arr[maxIndex]) maxIndex = j;
        }
        if (minIndex == maxIndex) break;
        BaseSort.swap(arr, i, minIndex);
        //防止最大值为i的情况。
        if (maxIndex == i) {
            BaseSort.swap(arr, length - 1 - i, minIndex);
        } else {
            BaseSort.swap(arr, length - 1 - i, maxIndex);
        }
    }
}

​ 代码中间唯一需要注意的地方也写了注释了,其他就没有什么可讲的了。代码我自己测试了几个用例,没有发现什么问题,但是测试较少,怀疑还是存在一些没有考虑到的情况。这里也欢迎大家指正。

题目

​ 还是把选择排序练习一下。这里上两个题目。

​ 思路比较简单,利用选择排序,找最大值,如果是第k大大元素,就返回,否则继续排序。优化的点其实也有:可以判断k是否大于数组中间长度,然后决定是找最大还是最小,能一定程度减少一些运算。但是因为时间问题,我实现的代码并没有做这个优化。具体的代码如下:

public int findKthLargest(int[] nums, int k) {
    int length = nums.length;
    int maxIndex;
    for (int i = 0; i < length; i++) {
        maxIndex = i;
        for (int j = i + 1; j < length; j++) {
            if (nums[j] > nums[maxIndex]) maxIndex = j;
        }
        if (i + 1 == k) return nums[maxIndex];
        int tmp = nums[maxIndex];
        nums[maxIndex] = nums[i];
        nums[i] = tmp;
    }
    return 0;
}

​ 这个也很简单,思路是直接用选择排序,可以用二元选择排序。没有什么可讲的点,但是因为力扣的时间限制,该代码没有通过。思路是正确的,后面这道题也可以选择其他时间复杂度较低的排序算法,例如:快速排序,归并排序等。选择排序思路如下:

public int[] sortArray(int[] nums) {
    int length = nums.length;
    int minIndex, maxIndex;
    for (int i = 0; i < length; i++) {
        minIndex = maxIndex = i;
        for (int j = i + 1; j < length - i; j++) {
            if (nums[j] < nums[minIndex]) minIndex = j;
            if (nums[j] > nums[maxIndex]) maxIndex = j;
        }
        if (minIndex == maxIndex) break;
        swap(nums, i, minIndex);
        //防止最大值为i的情况。
        if (maxIndex == i) {
            swap(nums, length - 1 - i, minIndex);
        } else {
            swap(nums, length - 1 - i, maxIndex);
        }
    }
    return nums;
}

public void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

​ 至此,选择排序基本讲完了,也欢迎大家补充、指正。

​ 就这样吧,结束。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值