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

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

本文与大家分享选择排序

目录

 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)

稳定性:

不稳定的排序

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【pytest、playwright】多账号同时操作

目录 方案实现思路&#xff1a; 方案一&#xff1a; 方案二&#xff1a; 方案实现思路&#xff1a; 依照上图所见&#xff0c;就知道&#xff0c;一个账号是pytest-playwright默认的环境&#xff0c;一个是 账号登录的环境 方案一&#xff1a; 直接上代码&#xff1a; imp…

Tensorflow2.0笔记 - 自定义Layer和Model

本笔记主要记录如何在tensorflow中实现自定的Layer和Model。详细内容请参考代码中的链接。 import time import tensorflow as tf from tensorflow import keras from tensorflow.keras import datasets, layers, optimizers, Sequential, metricstf.__version__ #关于自定义l…

JRT业务开发起步

这是一段充满挑战与奋斗的旅程&#xff0c;自第一行Java代码的写下起&#xff0c;便历经重重险阻。从细微的代码行&#xff0c;逐步汇聚成实用的工具类方法&#xff1b;从工具类方法的积累&#xff0c;逐渐构建起功能强大的工具包&#xff1b;再从工具包的整合&#xff0c;最终…

走进标杆企业——成套数字化标杆观摩游学(重庆站)

为了推进工业电气加工与设计的效率提升&#xff0c;加快企业数字化、网络化和智能化管理的步伐&#xff0c;利驰软件(苏州)有限公司&#xff08;下文简称利驰软件&#xff09;在重庆于2024年3月22日举办了一场成套数字化标杆观摩游学。此次为期一天的活动吸引了湘鄂渝地区专家们…

视频素材下载哪个软件好?几个素材库视频免费下载

在浩瀚的创意海洋中&#xff0c;找到完美的无水印视频素材犹如寻宝一般&#xff0c;每一段精彩的视频片段都能为您的作品增色不少。无论您是视频制作新手&#xff0c;还是经验丰富的专业人士&#xff0c;这里有全球各地的精选视频素材网站&#xff0c;旨在激发您的灵感&#xf…

EfficientSAM 项目排坑

EfficientSAM 项目排坑 任务过程记录创建环境运行示例 任务 跑通这个项目代码 过程记录 创建环境 readme里没有说具体怎么配置环境&#xff0c;所以可能对我来说还挺困难的。 现把项目git下来&#xff1a; git clone https://github.com/yformer/EfficientSAM.git cd Effi…

Flask Python:请求上下文和应用上下文

请求上下文和应用上下文详解 一、背景二、什么是上下文2.1、请求上下文2.2、应用上下文2.3、两种上下文的底层逻辑 三、写在最后 一、背景 在如何实现异步发送邮件的时候&#xff0c;遇到过这样一个报错 RuntimeError: Working outside of request context.This typically me…

【机器学习】数据探索---python主要的探索函数

在上一篇博客【机器学习】数据探索(Data Exploration)—数据质量和数据特征分析中&#xff0c;我们深入探讨了数据预处理的重要性&#xff0c;并介绍了诸如插值、数据归一化和主成分分析等关键技术。这些方法有助于我们清理数据中的噪声、消除异常值&#xff0c;以及降低数据的…

C语言内存函数(超详解)

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 点击主页&#xff1a;optimistic_chen和专栏&#xff1a;c语言&#xff0c; 创作不易&#xff0c;大佬们点赞鼓…

KIl5:Stm32L071下载出现flash download faild “cortex-m0+“的解决方法

首先看看有没有芯片&#xff0c;没有芯片下载一下 下载并在device选择对应的芯片 选择调试器 选择flash

C++ 二叉树OJ题

&#x1f493;博主CSDN主页:麻辣韭菜-CSDN博客&#x1f493;   ⏩专栏分类&#xff1a;C知识分享⏪   &#x1f69a;代码仓库:C高阶&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C知识   &#x1f51d;&#x1f51d; 前言 C二叉搜索树 这篇讲解了搜索二叉…

MySQL经验分享:Shell开发问题

背景 之前整理过Python连接使用MySQL的经验&#xff0c;链接如下&#xff1a; pymysql封装总结_pymysql封装类-CSDN博客 相比高级语言&#xff0c;Shell与MySQL开发使用相对会更麻烦一些&#xff1b;由于 shell是linux命令集的概称&#xff0c;是属于命令行的人机界面。Shel…

1688采集商品信息 马帮 店小秘 芒果采集API接口 java php

1688详情API接口是一种基于开放平台的应用程序接口&#xff0c;它能够实现与1688平台的数据交互&#xff0c;让商家能够更加方便地获取商品详情、库存信息、价格变动等重要数据。通过这一接口&#xff0c;商家可以实时掌握市场动态&#xff0c;快速响应消费者需求&#xff0c;从…

jenkins进行自动化部署

jenkins自动化部署 hello&#xff0c;大家好&#xff0c;前文我们已经下载好我们的jenkins了&#xff0c;下面我们用jenkins来实现自动化部署啦&#xff01; 一、下载插件 我们选择插件管理 一个是Maven Integration plugin&#xff0c;一个是 Publish Over SSH 这里因为作…

【uniapp】uniapp实现免密登录

文章目录 一、概要二、整体架构流程三、技术名词解释四 、技术细节1.存取token有效期&#xff1f;2.使用setStorageSync而不使用setStorage&#xff1f;3.使用onLaunch而不使用全局路由&#xff1f; 一、概要 打开一个网页或小程序的时候&#xff0c;我们有时候会自动进入主页…

嵌入式驱动学习第五周——驱动模块

前言 Linux驱动有两种运行方式&#xff0c;第一种是将驱动编译进Linux内核中&#xff0c;另一种是编译成模块&#xff0c;本篇博客来介绍一下驱动模块。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可…

Oladance、南卡、韶音开放式耳机值得买吗?爆款实测拒绝踩坑!

​在寻找最佳开放式耳机的过程中&#xff0c;我亲自试用并评估了市场上三个备受欢迎的品牌&#xff1a;Oladance、南卡和韶音。通过全面的多维度性能测试&#xff0c;我旨在为大家提供准确的购买指南&#xff0c;避免因选择不当而遭遇音质失真或佩戴不适的问题。 选择正确的耳…

window7 SP2

网上很多window7 SP1的更新教程&#xff0c;很少有sp2的教程 参考博客Windows 7 Service Pack 2 Download and Install (64-bit/32-bit) 即 转到 Microsoft 网站上的 Windows 7 Service Pack 2下载页面 。 选择与 Windows 7 版本相对应的 “下载 ”链接。 也可以 登录官网…

https安全性 带给im 消息加密的启发

大家好&#xff0c;我是蓝胖子&#xff0c;在之前# MYSQL 是如何保证binlog 和redo log同时提交的&#xff1f;这篇文章里&#xff0c;我们可以从mysql的设计中学会如何让两个服务的调用逻辑达到最终一致性&#xff0c;这也是分布式事务实现方式之一。今天来看看我们能够从http…