排序——选择排序(直接选择排序和堆排)

本专栏和大家分享关于排序的算法,其中有插入排(直接插入排序和希尔排序)、选择排序(直接选择排序和堆排)、交换排序(冒泡排序和快速排序)、归并排序以及其他非基于比较的排序

本文与大家分享选择排序

目录

 1.直接选择排序

优化:

时空复杂度:

稳定性:

2.堆排

向下调整的代码如下:

那么我们将数组向下调整后有什么用呢??

具体代码:

时空复杂度:

稳定性:

感谢您的访问!!!期待您的关注!!!


 1.直接选择排序

实际上就是在遍历的时候,每次记录i下标之后的最小值,放到i下标位置,这样最后就能形成一个有序数组,比较容易理解,我们直接通过代码演示

public static void selectSort(int[] array){
        for(int i = 0; i < array.length - 1; i++){
            int maxIndex = i;
            for(int j = i + 1; j < array.length; j++){
                if(array[j] > array[maxIndex]){
                    maxIndex = j;
                }
            }
            if(maxIndex != i){
                int tmp = array[maxIndex];
                array[maxIndex] = array[i];
                array[i] = tmp;
            }
        }
    }

但是时间复杂度太大!为O(N^2),是不稳定的排序

优化:

基于前面,我们可以在每一次遍历中不只是找最小值,而是最大值和最小值一起找

如图所示,我们定义一个左指针和一个右指针,接着利用i在left ~ right 里面遍历,找到一个最小值的下标和一个最大值的下标,将最小值与left的值进行交换,最大值与right的值进行交换,使得该区间的最小值和最大值分别在最左边和最右边的位置;接着 left ++,right--,缩小范围继续查找

但是有一个细节问题需要考虑:

如果我们某一段区间出现这种情况,我们找出最小值为1,最大值为10,交换left的元素与最小值:

接着我们要交换最大值与right的元素就会发现最大值原本是left上面的10,现在变成了1.这是因为我们的最大值刚好是left上的元素,而原来left上的元素又被最小值交换到minIndex的位置去了,因此当我们的maxIndex == left的时候,我们在交换完最小值后,需要将maxIndex = minIndex,去交换后的地方找原来的最大值

    public static void OptimizedSelectSort(int[] array){
        int left = 0;
        int right = array.length-1;
        while(left < right){
            int minIndex = left;
            int maxIndex = left;
            for(int i = left+1; i <= right; i++){
                if(array[i] < array[minIndex]){
                    minIndex = i;
                }
                if(array[i] > array[maxIndex]){
                    maxIndex = i;
                }
            }
            swap(array,left,minIndex);
            if(maxIndex == left){
                maxIndex = minIndex;
            }
            swap(array,right,maxIndex);
            left++;
            right--;
        }
    }

    private static void swap(int[] array,int i,int j){
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }

时空复杂度:

但是实际上时间复杂度还是O(N^2),分析时间复杂度的一种方法是考虑比较的次数。内层循环中,每个元素都可能与最大值和最小值进行比较,所以比较的次数仍然是 O(n^2)。虽然通过同时找到最大和最小值,每个元素可能会被比较两次,但这并不改变算法的时间复杂度。

空间复杂度为O(1)

稳定性:

是不稳定的排序:主要是因为在选择最小元素的过程中,相同元素的相对位置可能被打乱。


2.堆排

实际上认识了优先级队列的向下调整就能够理解堆排序

如果我们有如上图这样的数据,我们怎么将它设置为大根堆呢??

我们采用从最后一棵子树开始,依次向下调整的方法

假设每一棵子树的父亲节点下标为parent,子节点为child,那么最后一棵子树的子节点下标为 arr.length - 1,就能得到最后一棵子树的父亲节点下标为parent = (child - 1) / 2,即(arr.length - 1 ) /2 ;那么我们就从(arr.length - 1 ) /2 这个节点往前遍历,直到parent < 0,每次遍历都要针对每课子树进行向下调整

由于我们要建立的是大根堆,那么要求每棵子树的父亲节点都要大于任意一个子节点,那么我们就要在子节点里面找到一个最大的子节点,判断这个子节点是否大于父亲节点,如果大于,则交换

以4下标为根节点的子树已经判断完了,接下来parent--,判断以3下标为节点的所有子树

找到子节点中最大的一个,即为8,判断 9 > 4,那么9 与 4交换

那么以3下标为根节点的子树也就判断完了,接下来判断以2为节点的子树

可以看到,此时子树就不止一棵了,我们先判断以2为父亲节点的树,找到子节点中最大的,为10, 10 > 2,那么10与2交换,

此时我们会发现,交换完后,以4下标为父亲节点的树就不满足大根堆的要求了,因此我们要让parent = child,再继续向下调整,直到每课子树都满足向下调整的要求,交换完后是这样的

 

然后parent继续--,继续重复上述的流程即可

向下调整的代码如下:

public static void heap(int[] array){
         for(int parent = (array.length - 1 - 1) / 2; parent >= 0; parent--){
             siftDown(array,parent);
         }
     }
 ​
     private static void siftDown(int[] array,int parent){
         int child = 2 * parent + 1;
         while(child < array.length){
             if(child + 1 < array.length && array[child] < array[child+1]){//找到子节点最大的一个
                 child++;
             }
             if(array[parent] < array[child]){
                 swap(array,parent,child);
                 parent = child;
                 child = 2 * parent + 1;
             }else{
                 break;//不需要交换则说明这颗子树满足条件
             }
 ​
         }
     }
 ​
     private static void swap(int[] array,int i,int j) {
         int tmp = array[i];
         array[i] = array[j];
         array[j] = tmp;
     }

那么我们将数组向下调整后有什么用呢??

如图所示,我们以数组{6,4,7,5,8,3,9,2,10,1}建立完大根堆后,堆顶元素就是数组里面最大的元素,那么我们如果要得到增序列,就可以将堆顶元素与最后一个元素进行交换,就是将最大的数往后放接着再次进行向下调整,但是此时的向下调整不包括刚刚放进去的最大值,这样我们就能将第二大的元素通过向下调整放到堆顶,再次进行交换...依次类推

具体代码:

 public static void heapSort(int[] array){
        if(array.length == 0){
            return;
        }
        for(int parent = (array.length-1-1) / 2; parent >= 0; parent--){
            siftDown(array,parent,array.length);
        }
        int end = array.length - 1;
        while(end > 0){
            swap(array,0,end);
            siftDown(array,0,end);
            end--;
        }
    }

    private static void siftDown(int[] array,int parent,int end){
        int child = 2 * parent + 1;
        while(child < end){
            if(child + 1 < end&& array[child] < array[child+1]){//找到子节点最大的一个
                child++;
            }
            if(array[parent] < array[child]){
                swap(array,parent,child);
                parent = child;
                child = 2 * parent + 1;
            }else{
                break;//不需要交换则说明这颗子树满足条件
            }

        }
    }

    private static void swap(int[] array,int i,int j) {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }

时空复杂度:

堆排序包括两个主要步骤:建堆和排序。建堆过程的时间复杂度为O(n),排序过程,需要遍历每个节点,将第一个节点(最大的节点)放到末尾,同时每次都要进行向下调整,时间复杂度为O(n log n)。因此,整体的时间复杂度为O(n + n log n),简化后为O(n log n)。

空间复杂度为O(1)

稳定性:

不稳定的排序

在堆排序中,每次从堆中取出最大或最小元素时,都会与堆中的最后一个元素交换,然后重新调整堆以维持堆的性质。这个交换过程可能会导致相同元素的相对顺序发生改变,因此堆排序是不稳定的。

感谢您的访问!!!期待您的关注!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/507091.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python处理yaml文件

YAML&#xff08;YAML Ain’t Markup Language&#xff09;是一种人类可读的数据序列化格式&#xff0c;它与JSON格式类似&#xff0c;但具有更高的可读性。相比JSON&#xff0c;YAML更注重人类可读性&#xff0c;因此在配置文件、数据序列化和交换方面具有一定优势。它支持注释…

AI+云平台|全闪云底座迎战

AI融万物之势席卷而来 人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;英文缩写为AI。它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 行业特点 AI场景中80%以上是小文件&#xff0c;以非结构化数据为…

【Blockchain】GameFi | NFT

Blockchain GameFiGameFi顶级项目TheSandbox&#xff1a;Decentraland&#xff1a;Axie Infinity&#xff1a; NFTNFT是如何工作的同质化和非同质化区块链协议NFT铸币 GameFi GameFi是游戏和金融的组合&#xff0c;它涉及区块链游戏&#xff0c;对玩家提供经济激励&#xff0c…

【学习】如何成为资深的软件测试工程师“大神”?

一个优秀的软件测试工程师不仅需要有深厚的技术知识和经验&#xff0c;还需要有良好的沟通能力、分析能力和问题解决能力。总的来说&#xff0c;一个"大神"一样的软件测试工程师应该是一个全面的技术专家&#xff0c;同时还需要有出色的沟通和问题解决能力&#xff0…

第十三届蓝桥杯国赛真题 Java C 组【原卷】

文章目录 发现宝藏试题 A: 斐波那契与 7试题 B: 小蓝做实验试题 C: 取模试题 D: 内存空间试题 E \mathrm{E} E : 斐波那契数组试题 F: 最大公约数试题 G: 交通信号试题 I: 打折试题 J: 宝石收集 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#x…

nodejs+java+python高校食堂外卖点餐安全检查系统2k3o

开发语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;VScode本文的研究目标是以高校校园外卖点餐为对象&#xff0c;使其南京某高校校园外卖点餐为目标&#xff0c;使得南京某高校校园外卖点餐…

计算机网络-RIP动态路由协议简介

一、概述 前面我们学习了动态路由协议按照工作机制及算法划分可以分为&#xff1a;距离矢量路由协议DV型和链路状态路由协议LS型。RIP就是典型的距离矢量路由协议&#xff0c;但是实际工作中用得已经比较少了。 距离矢量路由协议DV: RIP 链路状态路由协议LS: OSPF IS-IS 二、RI…

3.2、单选框(Radio)

Radio是单选框组件,通常用于提供相应的用户交互选择项,同一组的Radio中只有一个可以被选中。 创建单选框 该接口用于创建一个单选框,其中 value 是单选框的名称,group 是单选框的所属群组名称。checked 属性可以设置单选框的状态,状态分别为 false 和 true 时,设置为 t…

《极客时间TonyBai go语言第一课》学习笔记

文章目录 前置篇显式组合并发 入门篇Go 包的初始化次序![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/1388d0d1bddd4a37b98eba5fcb41fc4d.png)初始化一个项目 大纲 前置篇 显式 在 C 语言中&#xff0c;下面这段代码可以正常编译并输出正确结果&#xff1a; #i…

备考ICA----Istio实验12---配置双向TLS Istio Ingress Gateway实验

备考ICA----Istio实验12—配置双向TLS Istio Ingress Gateway实验 本实验部分配置延续上个Istio实验11 1. 重新配置secret 重新配置secret使其带有ca证书可以验证客户端证书是否合法 先删除原有secret,再配置新的secret # 删除原tls类型的secret kubectl -n istio-system d…

【C】leetcode力扣—— 141. 环形链表Ⅰ

目录 141. 环形链表 Ⅰ题目解题思路分析暴力求解&#xff1f;&#xff1f;快慢指针 代码 141. 环形链表 Ⅰ 题目链接: https://leetcode.cn/problems/linked-list-cycle/description/ 题目 题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某…

【MySQL笔记】SELECT COUNT(*) 的时候,加不加where条件有差别吗?

文章目录 前言实验结论 前言 这部分很多帖子都只在问题里罗列下&#xff0c;好像也没详细解答 其实就是跟InnoDB优先走二级索引的优化有关&#xff0c;前面也提到了”优化的前提是查询语句中不包含where条件和group by条件“ 还不太了解这个优化的朋友可以看上一篇帖子 实验 …

【C++程序员的自我修炼】基础语法篇(二)

风力掀天浪打头 只须一笑不须愁 目录 内联函数 概念&#x1f49e; 性质 ⭐ 不建议变量分离 inline的优劣势 inline的局限性 auto关键字 auto的概念&#x1f49e; auto的使用细则&#x1f49e; auto不能推导的场景 &#x1f49e; auto基于范围的for循环&#x1f49e; 指针空值n…

谈谈对CPU IOwait的理解

谈谈对CPU IOwait的理解 %iowait表示在一个采样周期内有百分之几的时间属于以下情况&#xff1a;CPU空闲并且有仍未完成的I/O请求&#xff08;如果单纯是CPU空闲&#xff0c;但是并没有IO请求&#xff0c;那么这个时间就是CPU的idle时间&#xff09;&#xff0c;两个条件必须同…

JAVA学习笔记21

1.IDEA的使用 1.ctrl B 快速定位到方法 2.ctrl Y 快速删除行 3.ctrl D 快速复制行 4.ctrl H 查看继承的层级关系 5.快速格式化代码 ctrl shift L 6.alt R 快速允许程序 7.ctrl / 快速添加注释 1.包(软件包) 1.1包的三大作用 1.区分相同名字的类 2.当类很多的…

宝宝洗衣机买几公斤?四款顶尖婴儿洗衣机合集分享

由于婴儿类衣服的数目以及体积&#xff0c;一般婴儿洗衣机的体积比普通的家用洗衣机要小&#xff0c;而且在功能上比传统的大型洗衣机多了一个高温蒸煮除菌的功能。婴儿洗衣机和传统的大型洗衣机一样&#xff0c;都是具有着波轮式清洗方式和滚筒式清洗方式两种不同的选择&#…

【C++】Google Gtest测试框架的使用

本文首发于 ❄️慕雪的寒舍 gtest模块的安装参考站内教程 ubuntu安装google gtest 本文使用的gtest版本为1.14.0&#xff1b; 1.gtest是用来干嘛的&#xff1f; google gtest是一个c的单元测试模块&#xff0c;它提供了一系列规范化的宏&#xff0c;来帮助我们进行函数的单元…

Linux之 线程池 | 单例模式的线程安全问题 | 其他锁

目录 一、线程池 1、线程池 2、线程池代码 3、线程池的应用场景 二、单例模式的线程安全问题 1、线程池的单例模式 2、线程安全问题 三、其他锁 一、线程池 1、线程池 线程池是一种线程使用模式。线程池里面可以维护一些线程。 为什么要有线程池&#xff1f; 因为在…

一文教会女朋友学会日常Git使用!Git知识总结

文章目录 一文教会女朋友学会日常Git使用&#xff01;Git知识总结一、git基本知识了解1.git简介2.git区域了解3.git常用命令 二、常用工作场景1.克隆远程仓库&#xff0c;把仓库代码拉到本地2.推送代码到远程仓库&#xff08;1&#xff09;本地代码和远程仓库版本相同&#xff…

细谈SolidWorks教育版的一些基础知识

SolidWorks教育版是一款广泛应用于工程设计和教育领域的三维建模软件。它具备直观易用的操作界面和强大的设计功能&#xff0c;为学生提供了一个学习和实践的平台。在本文中&#xff0c;我们将详细探讨SolidWorks教育版的一些基础知识&#xff0c;帮助初学者更好地了解和掌握这…