java 排序算法之选择排序

目录
  • 基本介绍
  • 基本思想
  • 思路分析
  • 代码实现
    • 演变过程
    • 优化
    • 算法函数封装
    • 大量数据耗时测试

基本介绍

选择排序(select sorting)也属于内部排序法,是从欲排序的数据中,按指定的规则选出来某个元素,再依规定交换位置后达到排序的目的。

它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

基本思想

选择排序(select sorting)也是一种简单直观的排序方法。

基本思想为:

注:n 是数组大小

  • 第一次从 arr[0]~arr[n-1] 中选取最小值,与 arr[0] 交换
  • 第二次从 arr[1]~arr[n-1] 中选取最小值,与 arr[1] 交换
  • 第 i 次从 arr[i-1]~arr[n-1] 中选取最小值,与 arr[i-1] 交换
  • 依次类推,总共通过 n - 1 次,得到一个按排序码从小到大排列的有序序列

思路分析

动图:

说明:

1.选择排序一共有数组大小 - 1 轮排序

2.每 1 轮排序,又是一个循环,循环的规则

①先假定当前这轮循环的第一个数是最小数

②然后和后面每个数进行比较,如果发现有比当前数更小的数,则重新确定最小数,并得到下标

③当遍历到数组的最后时,就得到本轮最小的数

④和当前循环的第一个数进行交换

代码实现

要求:假设有一群牛,颜值分别是 101,34,119,1 ,请使用选中排序从低到高进行排序

演变过程

使用逐步推导的方式,进行讲解排序,容易理解。

推导每一步的演变过程,便于理解。

​ 这是一个很重要的思想:
​ 一个算法:先简单 --> 做复杂:
​ 就是可以把一个复杂的算法,拆分成简单的问题 -> 逐步解决

    @Test
    public void processDemo() {
        int arr[] = {101, 34, 119, 1};
        System.out.println("原始数组:" + Arrays.toString(arr));
        processSelectSort(arr);
    }

    public void processSelectSort(int[] arr) {
        // 第 1 轮:
        // 原始数组:101, 34, 119, 1
        // 排序后:  1, 34, 119, 101
        int min = arr[0]; // 先假定第一个数为最小值
        int minIndex = 0;
        for (int j = 0 + 1; j < arr.length; j++) {
            // 挨个与最小值对比,如果小于,则进行交换
            if (min > arr[j]) {
                // 如果后面的值比当前的 min 小,则重置min为这个数
                min = arr[j];
                minIndex = j;
            }
        }
        // 第 1 轮结束后,得到了最小值
        // 将这个最小值与 arr[0] 交换
        arr[minIndex] = arr[0];
        arr[0] = min;
        System.out.println("第 1 轮排序后:" + Arrays.toString(arr));

        // 第 2 轮
        // 当前数组:1, 34, 119, 101
        // 排序后:  1, 34, 119, 101
        min = arr[1];
        minIndex = 1;
        // 第二轮,与第 3 个数开始比起
        for (int j = 0 + 2; j < arr.length; j++) {
            // 挨个与最小值对比,如果小于,则进行交换
            if (min > arr[j]) {
                // 如果后面的值比当前的 min 小,则重置min为这个数
                min = arr[j];
                minIndex = j;
            }
        }
        // 第 2 轮结束后,得到了最小值
        // 将这个最小值与 arr[1] 交换
        arr[minIndex] = arr[1];
        arr[1] = min;
        System.out.println("第 2 轮排序后:" + Arrays.toString(arr));

        // 第 3 轮
        // 当前数组:1, 34, 119, 101
        // 排序后:  1, 34, 101, 119
        min = arr[2];
        minIndex = 2;
        // 第二轮,与第 4 个数开始比起
        for (int j = 0 + 3; j < arr.length; j++) {
            // 挨个与最小值对比,如果小于,则进行交换
            if (min > arr[j]) {
                // 如果后面的值比当前的 min 小,则重置min为这个数
                min = arr[j];
                minIndex = j;
            }
        }
        // 第 3 轮结束后,得到了最小值
        // 将这个最小值与 arr[2] 交换
        arr[minIndex] = arr[2];
        arr[2] = min;
        System.out.println("第 3 轮排序后:" + Arrays.toString(arr));
    }

测试输出

原始数组:[101, 34, 119, 1]
第 1 轮排序后:[1, 34, 119, 101]
第 2 轮排序后:[1, 34, 119, 101]
第 3 轮排序后:[1, 34, 101, 119]

从上述的演变过程来看,发现了规律:循环体都是相同的,只是每一轮排序所假定的最小值的下标在递增。因此可以改写成如下方式

	  @Test
    public void processDemo2() {
        int arr[] = {101, 34, 119, 1};
        System.out.println("原始数组:" + Arrays.toString(arr));
        processSelectSort2(arr);
    }

    public void processSelectSort2(int[] arr) {
        // 把之前假定当前最小值的地方,使用变量 i 代替了
        // 由于需要 arr.length -1 轮,所以使用外层一个循环,就完美的解决了这个需求
        for (int i = 0; i < arr.length - 1; i++) {
            int min = arr[i]; // 先假定第一个数为最小值
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                // 挨个与最小值对比,如果小于,则进行交换
                if (min > arr[j]) {
                    // 如果后面的值比当前的 min 小,则重置min为这个数
                    min = arr[j];
                    minIndex = j;
                }
            }
            // 第 i 轮结束后,得到了最小值
            // 将这个最小值与 arr[i] 交换
            arr[minIndex] = arr[i];
            arr[i] = min;
            System.out.println("第 " + (i + 1) + " 轮排序后:" + Arrays.toString(arr));
        }
    }

测试输出

原始数组:[101, 34, 119, 1]
第 1 轮排序后:[1, 34, 119, 101]
第 2 轮排序后:[1, 34, 119, 101]
第 3 轮排序后:[1, 34, 101, 119]

由此可以得到,选择排序的时间复杂度是 o(n²),因为是一个嵌套 for 循环

结果是一样的,但是你会发现,在第 1 轮和第 2 轮的序列是一样的,但是代码中目前也进行了交换,可以优化掉这一个点

优化

    public void processSelectSort2(int[] arr) {
        // 把之前假定当前最小值的地方,使用变量 i 代替了
        // 由于需要 arr.length -1 轮,所以使用外层一个循环,就完美的解决了这个需求
        for (int i = 0; i < arr.length - 1; i++) {
            int min = arr[i]; // 先假定第一个数为最小值
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                // 挨个与最小值对比,如果小于,则进行交换
                if (min > arr[j]) {
                    // 如果后面的值比当前的 min 小,则重置min为这个数
                    min = arr[j];
                    minIndex = j;
                }
            }
            // 第 i 轮结束后,得到了最小值
            // 将这个最小值与 arr[i] 交换
            //但如果minIndex没有改变,也就是最小值未发生改变,则不需要执行后面的交换了
            if (minIndex != i) {
                arr[minIndex] = arr[i];
            	arr[i] = min;
            }
            System.out.println("第 " + (i + 1) + " 轮排序后:" + Arrays.toString(arr));
        }
    }

测试输出

原始数组:[101, 34, 119, 1]
第 1 轮排序后:[1, 34, 119, 101]
第 3 轮排序后:[1, 34, 101, 119]

则可以看到,第二轮就跳过了交换这一个步骤,从而优化了这个算法所要花费的时间。

算法函数封装

@Test
public void selectSortTest() {
    int arr[] = {101, 34, 119, 1};
    System.out.println("升序");
    System.out.println("原始数组:" + Arrays.toString(arr));
    selectSort(arr, true);
    System.out.println("排序后:" + Arrays.toString(arr));
    System.out.println("降序");
    System.out.println("原始数组:" + Arrays.toString(arr));
    selectSort(arr, false);
    System.out.println("排序后:" + Arrays.toString(arr));
}

/**
 * 选择排序算法封装
 *
 * @param arr 要排序的数组
 * @param asc 升序排列,否则降序
 */
public void selectSort(int[] arr, boolean asc) {

    // 把之前假定当前最小值的地方,使用变量 i 代替了
    // 由于需要 arr.length -1 轮,所以使用外层一个循环,就完美的解决了这个需求
    for (int i = 0; i < arr.length - 1; i++) {
        int current = arr[i]; // 先假定第一个数为最小值
        int currentIndex = i;
        for (int j = i + 1; j < arr.length; j++) {
            // 挨个与最小值对比,如果小于,则进行交换
            if (asc) {
                if (current > arr[j]) {
                    // 如果后面的值比当前的 min 小,则重置min为这个数
                    current = arr[j];
                    currentIndex = j;
                }
            } else {
                if (current < arr[j]) {
                    // 如果后面的值比当前的 min 大,则重置为这个数
                    current = arr[j];
                    currentIndex = j;
                }
            }
        }
        // 第 i 轮结束后,得到了最小/大值
        // 将这个值与 arr[i] 交换
        //但如果minIndex没有改变,也就是最小值未发生改变,则不需要执行后面的交换了
        if (currentIndex == i) {
            arr[currentIndex] = arr[i];
        	arr[i] = current;
        }
    }
}

测试输出

升序
原始数组:[101, 34, 119, 1]
排序后:[1, 34, 101, 119]
降序
原始数组:[1, 34, 101, 119]
排序后:[119, 101, 34, 1]

大量数据耗时测试

排序随机生成的 8 万个数据

 @Test
    public void bulkDataSort() {
        int max = 80_000;
        int[] arr = new int[max];
        for (int i = 0; i < max; i++) {
            arr[i] = (int) (Math.random() * 80_000);
        }

        Instant startTime = Instant.now();
        selectSort(arr, true);
//        System.out.println(Arrays.toString(arr));
        Instant endTime = Instant.now();
        System.out.println("共耗时:" + Duration.between(startTime, endTime).toMillis() + " 毫秒");
    }

多次运行测试输出

共耗时:2983 毫秒
共耗时:3022 毫秒

冒泡排序和选择排序的时间复杂度虽然都是 o(n²),但由于冒泡排序每一步有变化都要交换位置,导致了消耗了大量的时间,所以选择排序相对冒泡排序所花费的时间要更少。

关于冒泡排序请看java 排序算法之冒泡排序

到此这篇关于java 排序算法之选择排序的文章就介绍到这了,更多相关java 选择排序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java对数组实现选择排序算法的实例详解

    一. 算法描述     选择排序:比如在一个长度为N的无序数组中,在第一趟遍历N个数据,找出其中最小的数值与第一个元素交换,第二趟遍历剩下的N-1个数据,找出其中最小的数值与第二个元素交换......第N-1趟遍历剩下的2个数据,找出其中最小的数值与第N-1个元素交换,至此选择排序完成. 以下面5个无序的数据为例: 56 12 80 91 20(文中仅细化了第一趟的选择过程) 第1趟:12 56 80 91 20 第2趟:12 20 80 91 56 第3趟:12 20 56 91 80 第4趟

  • java数据结构排序算法之树形选择排序详解

    本文实例讲述了java数据结构排序算法之树形选择排序.分享给大家供大家参考,具体如下: 这里我们就来说说选择类排序之一的排序:树形选择排序 在简单选择排序中,每次的比较都没有用到上次比较的结果,所以比较操作的时间复杂度是O(N^2),想要降低比较的次数,则需要把比较过程中的大小关系保存下来.树形选择排序是对简单选择排序的改进. 树形选择排序:又称锦标赛排序(Tournament Sort),是一种按照锦标赛的思想进行选择排序的方法.首先对n个记录的关键字进行两两比较,然后在n/2个较小者之间再进

  • Java实现选择排序算法的实例教程

    选择排序概念 选择排序也是一种交换排序算法,和冒泡排序有一定的相似度,因此个人认为选择排序可以视为冒泡排序的一种改进算法.它的思路是这样的: 设现在要给数组arr[]排序,它有n个元素. 1对第一个元素(Java中,下标为0)和第二个元素进行比较,如果前者大于后者,那么它一定不是最小的,但是我们并不像冒泡排序一样急着交换.我们可以设置一个临时变量a,存储这个目前最小的元素的下标.然后我们把这个目前最小的元素继续和第三个元素做比较,如果它仍不是最小的,那么,我们再修改a的值.如此直到和最后一个元素

  • JAVA十大排序算法之选择排序详解

    目录 选择排序 代码实现 动图演示 代码实现 时间复杂度 算法稳定性 总结 选择排序 1.找到数组中最大(或最小)的元素 2.将它和数组的第一个元素交换位置(如果第一个元素就是最大(小)元素那么它就和自己交换) 3.在剩下的元素中找到最大(小)的元素,将它与数组的第二个元素交换位置.如此往复,直到将整个数组排序. 代码实现 对下面数组实现排序:{87, 23, 7, 43, 78, 62, 98, 81, 18, 53, 73, 9} 动图演示 代码实现 public class Selecti

  • Java排序算法之选择排序

    一.选择排序 选择排序就是在每一次遍历过程中将数组中值最小的排到当前的第一位. 总共需要(数组长度-1)次遍历,在每次遍历中假定第一位索引的值为最小值,然后与下一个值对比,如果最小索引所在值大于其他值就将小的那一个索引当作最小值索引,接着继续对比最小索引所在值与下一个索引的值,重复此操作,最终就会在此次遍历中得到最小值及其索引,将最小值与第一位的值进行交换,这样就将最小值放到了数组开头,完成本次遍历. 选择排序的时间复杂度为O(N^2) 二.代码实现 package com.example.al

  • java排序算法之_选择排序(实例讲解)

    选择排序是一种非常简单的排序算法,从字面意思我们就可以知道,选择就是从未排序好的序列中选择出最小(最大)的元素,然后与第 i 趟排序的第 i-1(数组中下标从 0 开始) 个位置的元素进行交换,第 i 个元素之前的序列就是已经排序好的序列.整个排序过程只需要遍历 n-1 趟便可排好,最后一个元素自动为最大(最小)值. 举个小例子: arr[] = {3,1,2,6,5,4} 第 1 趟排序: index = 0, min = 1, 交换后 -->  1,3,2,6,5,4 第 2 趟排序: in

  • java排序算法之选择排序详解

    本文实例为大家分享了java排序算法之选择排序的具体代码,供大家参考,具体内容如下 选择排序 选择排序的思路是这样的:首先,找到数组中最小的元素,拎出来,将它和数组的第一个元素交换位置,第二步,在剩下的元素中继续寻找最小的元素,拎出来,和数组的第二个元素交换位置,如此循环,直到整个数组排序完成. 至于选大还是选小,这个都无所谓,你也可以每次选择最大的拎出来排,也可以每次选择最小的拎出来的排,只要你的排序的手段是这种方式,都叫选择排序. (有序区,无序区).在无序区里找一个最小的元素跟在有序区的后

  • Java实现的各种排序算法(插入排序、选择排序算法、冒泡排序算法)

    一.插入排序算法实现java版本 public static int[] insert_sort(int[] a) { for (int i = 0; i < a.length; i++) { for(int j=i+1;j>0&&j<a.length;j--) { if(a[j]<a[j-1]) { int tmp = a[j]; //这样定义初始化逻辑上是可以的,j变量,每次tmp的值变化的 a[j] = a[j-1]; a[j-1] = tmp; } } }

  • java 排序算法之选择排序

    目录 基本介绍 基本思想 思路分析 代码实现 演变过程 优化 算法函数封装 大量数据耗时测试 基本介绍 选择排序(select sorting)也属于内部排序法,是从欲排序的数据中,按指定的规则选出来某个元素,再依规定交换位置后达到排序的目的. 它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾.以此类推,直到所有元素均排序完毕. 基本思想 选择排序(select sorting)也是一种简单直

  • Java 十大排序算法之选择排序刨析

    目录 选择排序原理 选择排序API设计 选择排序代码实现 选择排序的时间复杂度 选择排序原理 ①假设第一个索引处的元素为最小值,和其他值进行比较,如果当前的索引处的元素大于其他某个索引处的值,则假定其他某个索引处的值为最小值,最后找到最小值所在的索引 ②交换第一个索引处和最小值所在的索引处的值 选择排序API设计 类名 Selection 构造方法 Selection():创建Selection对象 成员方法 1.public static void sort(Comparable[] a):对

  • Python排序算法之选择排序定义与用法示例

    本文实例讲述了Python排序算法之选择排序定义与用法.分享给大家供大家参考,具体如下: 选择排序 选择排序比较好理解,好像是在一堆大小不一的球中进行选择(以从小到大,先选最小球为例): 1. 选择一个基准球 2. 将基准球和余下的球进行一一比较,如果比基准球小,则进行交换 3. 第一轮过后获得最小的球 4. 在挑一个基准球,执行相同的动作得到次小的球 5. 继续执行4,直到排序好 时间复杂度:O(n^2).  需要进行的比较次数为第一轮 n-1,n-2....1, 总的比较次数为 n*(n-1

  • C语言排序算法之选择排序(直接选择排序,堆排序)

    目录 前言 一.直接选择排序 1.1 算法思想 1.2 代码实现 1.3 直接选择排序的特征总结 二.堆排序 2.1 什么是堆? 2.2 判断是否是堆 2.3 向下调整算法 2.4 自底向上的建堆方式 2.5 代码实现 2.6 堆排序的特性总结 2.7 堆排序的特性总结 前言 本期为大家带来的是常见排序算法中的选择排序,主要有直接选择排序以及——堆排序(有点难理解),包您一看就会,快来试试吧~ 一.直接选择排序 1.1 算法思想 每一次从待排序的数据元素中选出最小(或最大的)的一个元素,存放在序

  • JavaScript实现经典排序算法之选择排序

    表现最稳定的排序算法之一,因为无论什么数据进去都是O(n²)的时间复杂度.....所以用到它的时候,数据规模越小越好.唯一的好处可能就是不占用额外的内存空间. 1)算法原理 先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾.以此类推,直到所有元素均排序完毕. 2)算法描述和实现 n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果.具体算法描述如下: <1>初始状态:无序区为R[1..n],有序区为

  • Java数据结构与算法之选择排序(动力节点java学院整理)

    每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完. 代码 public class ChoseSort { //constructor without parameters public ChoseSort(){}; //constructor with parameters public int[] ChoseSort(int[] intArr){ for(int i=0;i<intArr.length-1;i++){ int

  • 图解Java经典算法冒泡选择插入希尔排序的原理与实现

    目录 一.冒泡排序 1.基本介绍 2.代码实现 二. 选择排序 1.基本介绍 2.代码实现 三.插入排序 1.基本介绍 2.代码实现 四.希尔排序 1.基本介绍 2.代码实现(交换排序) 3.代码实现(移位排序) 一.冒泡排序 1.基本介绍 冒泡排序是重复地走访要排序的元素,依次比较两个相邻的元素,如果它们的顺序与自己规定的不符合,则把两个元素的位置交换.走访元素重复地进行,直到没有相邻元素需要交换为止,完成整个排序过程. 算法原理 1.比较相邻元素,如果前一个元素大于后一个元素,则交换. 2.

随机推荐