4、由java实现的简单算法——选择排序(双向选择排序以及改进方法)

一  前言

如果对本系列产生什么疑问的话,  建议先下前言,  里面有我的联系方式,  教材的下载地址,   特殊词语的规定之类的........   链接地址: https://blog.csdn.net/qq_41057280/article/details/89209081 ;   最后, 以下说法仅为个人理解, 如有错误, 欢迎教正

二  介绍

选择排序(Selection sort),是一种通过不断选择剩余数组的元素来实现排序的算法。

具体的步骤如下:

  1. 从第一位开始遍历数组选出最小的元素将其放到第一位
  2. 从第二位开始遍历选出最小的元素放到第二位
  3. ......
  4. 从第n-1位开始遍历选出最小的元素放到第n-1位.
  5. 最后整个数组排序完成
     

三  java代码

首先,  先来个常规的照着步骤写一个

/**
* 选择排序
* 从第一位开始遍历数组选出最小的元素将其放到第一位
* 从第二位开始遍历选出最小的元素放到第二位
* ......
* 从第n-1位开始遍历选出最小的元素放到第n-1位.
* 整个数组排序完成
*/
public void sort(int[] arr) {
    int n = arr.length;// 数组长度
    int min = 0; // 最小值的下标

    for (int i=0; i<n-1; i++) {
        min = i;
        // 如果有比最小值小的,就更新下标
        for (int j=min+1; j<n; j++) {
            if (arr[j] < arr[min]) {
                min = j;
            }
        }
        // 如果最小值的下标不在开始位置, 则进行交换
        if (i != min) {
            Algorithm.swap(arr, min, i);
        }
        Algorithm.printArray(arr);
    }
}

这是一个非常简单而且十分直观的排序方法。虽然简单,但还是有需要注意的点。在排序过程中最小值可能在开始位置,所以不能直接交换,需要进行判断。

另外, 根据代码我们可以发现,这个算法的时间复杂度O(n²)。具体怎么算,这里就不列举了。 最后,如果待排序数组有数值相同的元素, 那么他们的相对先后顺序就会被破坏(后面的元素到前面去了,因为我们是顺序比较的),因此该算法是一个不稳定的排序算法。

不过,该算法是交换次数最少的排序算法,最多只会移动n-1次。 这应该也算得上他为数不多的优点

五  双向选择排序算法

基础的选择算法每一趟循环只能确保一个元素位置正确, 算法效率不高。 我们可以试着改进,比如说一次循环分别确定最大、小元素的位置,从而减少循环次数。 这就是双向选择排序算法

通俗点解释就是,每次排序都从待排序的无序数组中选出最大和最小值的索引,将最小值交换至无序表表头、最大值交换至无序表表尾,从而逐渐在无序表的两端形成有序表。 理论上,大小为n的数组只要进行n/2次排序即可。 

代码如下:

在排序的过程中,有可能出现最大值和最小值的索引与边界值重合,所以最后必须分情况进行判断。

ps:我总感觉这段判断很丑,有没有大佬愿意帮我改进下的

/**
* 双向选择排序算法 在选择算法的基础上,在一次循环中选择两个元素(最大和最小)。 以此减少循环次数提高效率
*/
public void doubleSelectionSort(int[] arr) {
    int n = arr.length;// 数组长度
    for (int i = 0; i < n / 2; i++) {
        int rangeL = i; // 待排序数组的左边界
        int rangeR = n - i - 1; // 待排序数组的右边界
        int min = rangeL;
        int max = rangeR;
        
        for (int j = rangeL; j <= rangeR; j++) {
            // 如果有比最小值小的,就更新最小值下标
            if (arr[j] < arr[min]) {
                min = j;
            }

            // 如果有比最大值大的,就更新最大值下标
            if (arr[j] > arr[max]) {
                max = j;
            }
        }
        // 注意特殊情况
        if (rangeL == min && rangeR == max) {
            // 位置正确,不改动
        } else if (rangeL == min) {
            // 最小值在开始位置,则交换最大值到结束位置
            // swap (max, rangeR)
            Algorithm.swap(arr, max, rangeR);
        } else if (rangeR == max) {
            // 最大值在结束位置,则交换最小值到开始位置
            // swap (max, rangeR)
            Algorithm.swap(arr, min, rangeL);
        } else if (rangeR == min && rangeL == max) {
            // 最大值在开始位置,最小值在结束位置
            // swap(rangeL, rangeR)
            Algorithm.swap(arr, rangeL, rangeR);
        } else if (rangeL == max) {
            // 最大值在开始位置,先交换最大值
            Algorithm.swap(arr, max, rangeR);
            Algorithm.swap(arr, min, rangeL);
        } else {
            // 正常交换
            Algorithm.swap(arr, min, rangeL);
            Algorithm.swap(arr, max, rangeR);
        }
        
        // 打印
        Algorithm.printArray(arr);
    }
}

虽然我是说这是选择排序的一种改进方式,但根据代码我们可以发现,这个算法的时间复杂度还是为O(n²)。而且比较次数也比原先要多,再加上最后的分情况讨论,使得算法的复杂性高于原算法、效率也不及原算法。 总结,这种改进毫无意义。

六、双向选择排序算法(改)

综上所述,普通的双排并没有对原来的选择排序算法改进优化。  主要问题在于最后交换前的分情况处理使算法变得复杂效率下降,如果我们能省略这一步的话,那才能真正意义上得到优化。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章