服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - java 排序算法之选择排序

java 排序算法之选择排序

2021-12-14 13:02lan00zi Java教程

本文主要讲解了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 次,得到一个按排序码从小到大排列的有序序列

 

思路分析

动图:

java 排序算法之选择排序

说明:

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

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

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

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

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

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

 

代码实现

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

java 排序算法之选择排序

演变过程

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

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

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

  @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 选择排序内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/ljz111/p/15205583.html

延伸 · 阅读

精彩推荐
  • Java教程xml与Java对象的转换详解

    xml与Java对象的转换详解

    这篇文章主要介绍了xml与Java对象的转换详解的相关资料,需要的朋友可以参考下...

    Java教程网2942020-09-17
  • Java教程Java8中Stream使用的一个注意事项

    Java8中Stream使用的一个注意事项

    最近在工作中发现了对于集合操作转换的神器,java8新特性 stream,但在使用中遇到了一个非常重要的注意点,所以这篇文章主要给大家介绍了关于Java8中S...

    阿杜7482021-02-04
  • Java教程升级IDEA后Lombok不能使用的解决方法

    升级IDEA后Lombok不能使用的解决方法

    最近看到提示IDEA提示升级,寻思已经有好久没有升过级了。升级完毕重启之后,突然发现好多错误,本文就来介绍一下如何解决,感兴趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程小米推送Java代码

    小米推送Java代码

    今天小编就为大家分享一篇关于小米推送Java代码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    富贵稳中求8032021-07-12
  • Java教程Java BufferWriter写文件写不进去或缺失数据的解决

    Java BufferWriter写文件写不进去或缺失数据的解决

    这篇文章主要介绍了Java BufferWriter写文件写不进去或缺失数据的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    这篇文章主要介绍了Java使用SAX解析xml的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java实现抢红包功能

    Java实现抢红包功能

    这篇文章主要为大家详细介绍了Java实现抢红包功能,采用多线程模拟多人同时抢红包,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙...

    littleschemer13532021-05-16
  • Java教程20个非常实用的Java程序代码片段

    20个非常实用的Java程序代码片段

    这篇文章主要为大家分享了20个非常实用的Java程序片段,对java开发项目有所帮助,感兴趣的小伙伴们可以参考一下 ...

    lijiao5352020-04-06