选择排序

前言

原理:每次循环对比找出最小/大值,将最值的元素交换至左侧

思想:直接选择排序(Straight Select Sort)算法思想:第一趟从n个元素的数据序列中选出关键字最小/大的元素并放在最前/后位置,下一趟从n-1个元素中选出最小/大的元素并放在最前/后位置。以此类推,经过n-1趟完成排序

案例分析

1、初始的无序数列 {5,8,6,3,1,7},希望对其升序排序

2、按照思路分析:

内层循环经过一轮对比后找到最小值,min = 1,下标为 index = 4;交换位置

代码实现

第 1 版代码

public static void straightSelectSort(int[] arr){

    //i不需要 = 数组最尾部元素,因为后面没有值对比了
for (int i = 0; i < arr.length - 1; i++) {
//设置每次循环的起始点为最小/大值
int min = arr[i];
//记录下最小/大值的下标
int index = i;
for (int j = i + 1; j < arr.length; j++) {
//升序排序>,降序排序<
if (min > arr[j]){
min = arr[j];
index = j;
}
}
//一轮对比完成后,将默认的最小值赋予到找到的最值下标位置
arr[index] = arr[i];
//把找到的真实最值放到前面
arr[i] = min;
}
}

这里其实有可能出现默认的最小值其实就是真正的最小值,所以一轮内层循环下来,是没有交换数据,可以添加哨兵,如果没有找到最小值,就不进行值的交换,减少交换次数。

第 2 版代码

public static void straightSelectSort(int[] arr){

    //i不需要 = 数组最尾部元素,因为后面没有值对比了
for (int i = 0; i < arr.length - 1; i++) {
//设置每次循环的起始点为最小/大值
int min = arr[i];
//记录下最小/大值的下标
int index = i;
//哨兵,记录是否找到最值,默认false
boolean isSwap = false;
for (int j = i + 1; j < arr.length; j++) {
//升序排序>,降序排序<
if (min > arr[j]){
min = arr[j];
index = j;
//找到最值,设置为true
isSwap = true;
}
}
if (isSwap){
//一轮对比完成后,将默认的最小值赋予到找到的最值下标位置
arr[index] = arr[i];
//把找到的真实最值放到前面
arr[i] = min;
}
}
}

直接选择排序算法复杂度分析:

如果数组中有**n个元素

第1轮循环是arr[0] 和arr[1] ...arr[n-1] 进行比较,次数为n-1 次,arr[0]放最值。

第2轮循环是arr[1] 和 arr[2]...arr[n-1] 进行比较,次数为n-2次,arr[1]放第二个最值。

所以不难得出它的比较的次数是n-1 + n-2 + n-3 + ....1 = n*(n-1)/2 。

时间复杂度为 = n^2/2- n/2 = n^2 ,O(n^2)

算法升级

分析

直接选择排序每一次查找只是找出最小值,可以这么改进,查找最小值的同时,找到一个最大值,然后将两者分别放在它们应该出现的位置,这样遍历的次数就会减少,同时添加哨兵,如果没有找到最值,不发生交换

以新的无序数列 {5,1,6,3,9,2,7,0}为例,按照上面的分析,初始状态如下:

排序过程如下:

交换最值,将最小值放到arr[left],最大值放到arr[right],同时left++,right--;准备下一轮循环,第一轮结果如下:

算法注意点:

(1) 第二轮开始对比前,我们可以发现,此时arr[left]arr[right]恰好是此轮的最值,因此应该加上哨兵,对此情况,内循环走完后,不进行值交换,判断条件:min == right && max == left

(2) 特别注意的地方:第三轮循环后,可以发现的点是,left = 2,right = 5,而结果是min = 5,max = 2,仔细看你就发现了,leftmin对应,而maxright对应,结果是值反面的的,所以在进行值交换的时候,进行一次就可以了,否则交换两次,就变成了巴黎铁塔翻过来又翻回去了,判断条件:min == right && max == left

进化版代码

public static void betterSelectSort(int[] arr) {

        //left指针指向无序边界起点,right指针指向终点,temp用作临时变量交换值
int left,right,temp;
//默认指向无序列表起点
left = 0;
//默认指向无序列表终点
right = arr.length - 1;
//记录每轮找到的最小值的下标
int min = left;
//记录每轮找到的最大值的下标
int max = right;
//当right >= left时,列表已经有序
//记录循环的次数
int index = 0;
while(left < right) {
min = left; //每轮开始前,默认无序列表起点为最小值
max = right; //每轮开始前,默认无序列表终点为最大值
//指针i从左往右扫描,找出最小值,最大值
for (int i=left; i<=right; i++) {
if (arr[i]<arr[min]) {
min = i; //通过比较,记录最小值的下标
}
if(arr[i]>arr[max]) {
max = i; //通过比较,记录最大值的下标
}
}
index++;
if (min == left && max == right){
System.out.println("第" + index + "轮循环没有找到最值,无需交换");
}else if (min == right && max == left){
//交换一次即可,交换两次的话,序列翻转,相当于没有交换
temp = arr[left];
arr[left] = arr[min];
arr[min] = temp;
}else {
//找到最小值,交换
temp = arr[left];
arr[left] = arr[min];
arr[min] = temp; //找到最大值,交换
temp = arr[right];
arr[right] = arr[max];
arr[max] = temp;
}
//确定最小/大值,指针向中间移动
left++;right--;
}
}

优化后代码虽然有效的减少了外层循环的次数,但其时间复杂度仍然是O(n^2)

文章为原创,转载请声明出处

更多文章,欢迎点赞关注,我的掘金:https://juejin.im/user/1151943919304840/posts

图解选择排序及算法优化(Java实现)的更多相关文章

  1. 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现)

    程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现) 程序员必知的8大排序(二)-------简单选择排序,堆排序(java实现) 程序员必知的8大排序(三)-------冒 ...

  2. 排序算法之选择排序的思想以及Java实现

    1 基本思想 选择排序的思想是,每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. 2,算法的实现(Java) package Algorit ...

  3. 排序基础之插入排序、冒泡排序、选择排序详解与Java代码实现

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6594533.html  一:插入排序==逐个往前相邻数比较交换,小的在前 第一轮:A[1]与A[0]比较,小的 ...

  4. 选择排序---堆排序算法(Javascript版)

    堆排序分为两个过程: 1.建堆. 堆实质上是完全二叉树,必须满足:树中任一非叶子结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字. 堆分为:大根堆和小根堆,升序排序采用大根堆,降序排序 ...

  5. java-直接选择排序

    直接选择排序是一种简单的排序方法,它每次从当前待排序的区间中选择出最小的元素,把该元素与该区间的第一个元素交换. 第一次从a[0]~a[n-1]中选取最小值,与a0]交换,第二次从a[1]~a[n-1 ...

  6. javascript数组排序算法之选择排序

    前言 作为一名程序员数组的排序算法是必须要掌握的,今天来图解----选择排序 选择排序原理 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大) ...

  7. 常用排序算法的Java实现 - 1

    学习编程语言时, 我们会接触到许多排序算法, 这里总结了一下常见的排序算法. 不定期更新. * 其实在Java中存在如Collections.sort()这样的方法来自动为我们排序, 不过学习排序算法 ...

  8. 【DS】排序算法之选择排序(Selection Sort)

    一.算法思想 选择排序是一种简单直观的排序算法.它的工作原理如下: 1)将序列分成两部分,前半部分是已经排序的序列,后半部分是未排序的序列: 2)在未排序序列中找到最小(大)元素,放到已排序序列的末尾 ...

  9. 常见排序算法总结 -- java实现

    常见排序算法总结 -- java实现 排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序. 线性时间 ...

随机推荐

  1. 生成对抗网络GAN介绍

    GAN原理 生成对抗网络GAN由生成器和判别器两部分组成: 判别器是常规的神经网络分类器,一半时间判别器接收来自训练数据中的真实图像,另一半时间收到来自生成器中的虚假图像.训练判别器使得对于真实图像, ...

  2. CPU:别再拿我当搬砖工了!

    数据搬运工 Hi,我是CPU一号车间的阿Q,有段日子没见面了. 还记得上回说到咱们厂里用上了DMA技术(太慢不能忍!CPU又拿硬盘和网卡开刀了!)之后,我们总算解放了,再也不用奔波于网卡.硬盘与内存之 ...

  3. 调试备忘录-J-Link RTT的使用(原理 + 教程 + 应用 + 代码)

    MCU:STM32F407VE MDK:5.29 IAR:8.32 目录--点击可快速直达 目录 写在前面 什么是RTT? RTT的工作原理 RTT的性能 快速使用教程 高级使用教程 附上测试代码 2 ...

  4. SQL Server 异常代码处理

    SQL Server使用TRY...CATCH 结构实现TSQL语句的错误处理,TRY命令负责监控语句执行的情况,如果有TSQL语句发生异常,并且严重级别(Severity Level)大于10,并且 ...

  5. WKWebView 网络请求Header 丢失

    WKWebView 是苹果手机上主要的H5加载控件,它相比UIWebView 有诸多优势.在次不做比较,但是它的坑缺比较多.网上也有很多的例子但是做的比较好的真不多,我在这里推荐俩博客供大家参考.ht ...

  6. 【算法•日更•第二期】查找算法:三分VS二分

    ▎前言:函数 如果你已经上过初二的数学课了,那么你十有八九会被函数折磨到吐血,这是一种中考压轴题类的题目,往往分类讨论到你恶心.不过没学过也不打紧,现场讲解一下: ☞『数学中的函数』 一般地,如果在一 ...

  7. golang目录

    基础 golang安装及vscode编辑器配置 golang基础结构 golang基础数据类型 golang复合数据结构 goalng函数 golang方法 golang接口 golang并发 gol ...

  8. Netbox 开源 IPAM 管理工具搭建详细流程

    原文链接:Netbox 开源 IPAM 管理工具搭建详细流程 参考资料:https://netbox.readthedocs.io/en/stable/ PostgreSQL数据库安装 1.yum 下 ...

  9. JS事件——添加、移除事件

    element.addEventListener(event, function, useCapture) 方法用于向指定元素添加事件句柄.   event: 必须.字符串,指定事件名.注意: 例 使 ...

  10. 尝试写一写4gl与4fd

    4gl DATABASE ds   GLOBALS "../../config/top.global"   DEFINE g_curs_index           LIKE t ...