数据结构——排序(3):交换排序(续)
目录
一、快速排序
(1)hoare版本
①思路
②过程图示
③思考
④代码实现
⑤代码解释
(2)挖坑法
①思路
②过程图示
③思考
④代码实现
⑤代码解释
(3)lomuto前后指针
①思路
②过程图示
③思考
④代码实现
⑤代码解释
(4)快速排序的复杂度
(5)非递归版本
①代码实现
②代码解释
二、写在最后
一、快速排序
我们上次学到了快速排序的递归方式,但是找基准值的函数(_QuickSort)如何实现呢?
(1)hoare版本
①思路
首先创建左右指针来寻找基准值。具体步骤为
一个指针从左到右找出比基准值大的数据,另一个指针从右到左找出比基准值小的数据,交换两者的位置,进入下一次循环。
②过程图示
1. 首先key指向第一个数据,left指向第二个数据,right指向最后一个数据;
2.right从右向左遍历找比key小的数据(3),left从左向右遍历找比key大的数据(7);
3.将两者交换位置;
4..right往后走一步,left往前走一步;(此时两者相遇)
5.right向左找比key小的数据(3),left向右找比key大的数据(9);(此时,left走到了right右边,跳出循环);
6.将right位置和key位置的数据交换位置,此时right位置的数据就是我们要找的key值(基准值);
7.基准值为6,此时基准值左侧的数据比其小,右侧的数据比其大。
③思考
1.若left==right是否继续循环?
场景1:过程图示中的例子,此处不再赘述。
假设left==right时不再进行循环,则:
此时得到基准值为6,但是不满足“基准值左边都是小于它的数据,基准值右边都是大于它的数据”。
场景2:
1. 首先key指向第一个数据,left指向第二个数据,right指向最后一个数据;
2.right从右向左遍历找比key小的数据(3),left从左向右遍历找比key大的数据(7);
3.将两者交换位置;
4.right往后走一步,left往前走一步;(此时两者相遇)
5.right找到了比基准值<=的数据(6),left找到了比基准值>=的数据(6);(此时,left走到了right右边,跳出循环);
6.将right位置和key位置的数据交换位置,此时right位置的数据就是我们要找的key值(基准值);
7.基准值为6,此时基准值左侧的数据比其小,右侧的数据比其大(或等于)。
场景3:
1. 首先key指向第一个数据,left指向第二个数据,right指向最后一个数据;
2.right从右向左遍历找比key小的数据(3),left从左向右遍历找比key大的数据(7);
3.将两者交换位置;
4.right往后走一步,left往前走一步;(此时两者相遇)
5.right找到了比基准值小的数据(4),left找到了比基准值大的数据(7);(此时,left走到了right右边,跳出循环);
6.将right位置和key位置的数据交换位置,此时right位置的数据就是我们要找的key值(基准值);
7.基准值为6,此时基准值左侧的数据比其小,右侧的数据比其大。
通过场景1我们得出left==right仍继续循环,否则在“相遇值大于key值”的情况下会出错!
2.当left或right指向的值与key相等时,是否进行交换?
我们以数组{6,6,6,8,6,6}为例:
(1)假设left或right指向的值与key相等时交换:
在第三次交换中,left和right相遇,我们不跳出循环(思考1中已经解释)。因此得到基准值为6。
(2)假设left或right指向的值与key相等时不交换:
1. 首先key指向第一个数据,left指向第二个数据,right指向最后一个数据;
2.right从右向左遍历找比key小的数据,没找到且越界了(此时left在right右边,跳出循环);
3.将right位置与key交换(right和key在同一个位置,相当于没交换);
4.基准值为6,那么没有左子树。
如果left或right指向的值与key相等时不交换,对于这种情况,分割后数据的个数为:n、n-1、n-2……并不是我们理想的类似于二叉树的分割,效率较低。
我们得出left或right指向的值与key相等时应该交换,否则效率会降低!
④代码实现
int _QuickSort(int* arr, int begin, int end)
{int left = begin;int right = end;int key = left;left++;while(left <= right){while(left <= right && arr[right] > arr[key]){right--;}while(left <= right && arr[left] < arr[key]){left++;}if(left <= right){swap(&arr[left++], &arr[right--]);}}swap(&arr[right], &arr[key]);return right;}
⑤代码解释
首先我们让left位于第二个数据位置,right位于最后一个数据的位置,假设key为第一个数据。在left<=right的情况下,right从右向左找小于基准值的数据,left从左向右找大于基准值的数据,当两者均找到时交换位置,(不要忘记让两者继续遍历),直至left>right跳出循环。
(2)挖坑法
①思路
创建两个指针left和right,第一个数据的位置为“坑”。right从右向左找出比基准值小的数据,放入“坑”中,当前位置变成新的“坑”;接着lleft从左向右找出比基准值大的数据,放入“坑”中,当前位置又变成新的“坑”。以此循环……最后将最开始“坑”位置的值放入当前位置的坑中,当前位置即基准值。
②过程图示
我们以数组{6,1,2,7,9,3}为例:
1.首先left、hole指向第一个数据,right指向最后一个数据;
2.right找到比基准值小的数据(3),将该位置的数据放入原来的坑中,该位置变成新的“坑” ;
3.left找到比新基准值大的数据(7),将该位置的数据放入原来的坑中,该位置变成新的“坑”;
4..right找到比新基准值<=的数据(7),将该位置的数据放入原来的坑中,该位置变成新的“坑” ;
5.将最开始坑位置的数据放在当前坑中,当前数据为基准值。
③思考
1.若left==right是否继续循环?
假设left==right继续循环:
我们得到基准值为6,不满足“基准值左边都是小于它的数据,基准值右边都是大于它的数据”。
因此若left==right时不继续循环 !
2.当left或right指向的值与key相等时,是否将其设为新的“坑”?
假设当left或right指向的值与key相等时,将其设为新的“坑”:
我们可以看到,如果将其设为新的坑,会降低效率。
因此,当left或right指向的值与key相等时,不必将其设为新的“坑”!
④代码实现
int _QuickSort(int* arr, int left, int right)
{int mid = arr[left];int hole = left;int key = arr[hole];while(left < right){while(left < right && arr[right] >= key){right--;}arr[hole] = arr[right];hole = right;while(left < right && arr[left] <= key){left++;}arr[hole] = arr[left];hole = left;}arr[hole] = key;return hole;
}
⑤代码解释
创建两个指针left和right,第一个数据的位置为“坑”。在left<right的情况下,right从右向左找出比基准值小的数据,放入“坑”中,当前位置变成新的“坑”;接着lleft从左向右找出比基准值大的数据,放入“坑”中,当前位置又变成新的“坑”。以此循环……最后将最开始“坑”位置的值放入当前位置的坑中,返回当前位置(即基准值)。
(3)lomuto前后指针
①思路
创建前后两个指针,从左向右找比基准值小的数据进行交换,使小的数据都排在基准值的左边。
②过程图示
我们以数组{6,1,2,7,9,3}为例:
1. prev指向第一个数据,cur指向第二个数据位置,key指向第一个数据位置;
2.此时cur指向的数据小于key,但是prev的下一个数据为cur;
3.让cur往后走一步;
4.此时cur指向的数据也小于key,但是prev的下一个数据仍为cur;
5.让cur继续往后走一步;
6.此时cur指向的数据小于key且prev的下一个数据不为cur,我们让prev和cur位置的数据交换位置;
7.cur继续往后走,此时越界,跳出循环;
8.让key和prev位置的数据交换;
9.此时prev位置的数据就是我们要找的基准值(prev左边的数据都比它小,prev右边的数据都比它大)。
③思考
1.当cur==right是否继续循环?
当然继续循环,在这个代码中,cur相当于在前面遍历,需要遍历到每个元素,而right位置的元素就是最后一个元素。
2.如果cur和key指向的元素相同,cur和prev是否交换?
其实两者情况的结果是一样的。
解释:
我们以数组{6,6,6,6,6}为例:
如果相等不交换:
如果相等交换:
因此,相等交不交换都是一样的,要么递归左区间,要么递归右区间(二叉树理想下为递归左右区间)。对于全部相等的数组,复杂度都很高。
④代码实现
int _QuickSort(int* arr, int left, int right)
{int prev = left;int cur = left + 1;int key = left;while(cur <= right){if(arr[cur] < arr[key] && ++prev != cur)//如果prev和cur相同就不进行交换{swap(&arr[cur], &arr[prev]);}cur++;}swap(&arr[key], &arr[prev]);return prev;
}
⑤代码解释
我们先假定第一个元素是基准值,用cur来递归数组的每一个元素,如果小于(或小于等于)基准值,我们设法将它放在前面,即将其放在cur前面的prev位置(prev是一直在++的),循环进行。最后将key和prev交换位置,返回的prev即为基准值。
(4)快速排序的复杂度
1.时间复杂度:O(N*logN);
2.空间复杂度:O(logN)。
(5)非递归版本
需要借助数据结构——栈 。
①代码实现
void QuickSortNonR(int* arr, int left, int right)
{Stack st;//初始化StackInit(&st);//入栈StackPush(&st, right);StackPush(&st, left);while(!StackEmpty(&st)){int begin = StackTop(&st);StackPop(&st);int end = StackTop(&st);StackPop(&st);//新数组int key = begin;int prev = begin;int cur = begin + 1;//找基准值while(cur <= end){if(arr[cur] < arr[key] && ++prev != cur){swap(&arr[prev], &arr[cur]);}cur++;}swap(&arr[key], &arr[prev]);key = prev;//右子树if(key + 1 < end){StackPush(&st, end);StackPush(&st, key + 1);}//左子树if(begin < key -1){StackPush(&st, key - 1);StackPush(&st, begin);}}StackDestroy(&st);
}
②代码解释
首先非递归实现排序,我们用到栈,也就是说用栈来模拟递归。
二、写在最后
至此,我们已经学习了插入排序、选择排序、交换排序,还剩下最后一个归并排序,我们下期见~
相关文章:

数据结构——排序(3):交换排序(续)
目录 一、快速排序 (1)hoare版本 ①思路 ②过程图示 ③思考 ④代码实现 ⑤代码解释 (2)挖坑法 ①思路 ②过程图示 ③思考 ④代码实现 ⑤代码解释 (3)lomuto前后指针 ①思路 ②过程图示 ③思考 ④代码实现 ⑤代…...

2024最新版本Python安装及开发环境配置(vscodepython)
python安装 去Python官网下载最新版本: 接下来请一步步按照图片操作: 这样子就安装完成了 测试Python安装是否成功 先打开终端 右键Windows徽标,点击终端 然后输入python,如果如下图所示,就说明安装成功࿰…...
机器学习的定义
机器学习 机器学习的定义 机器学习是人工智能的一个分支,它使计算机系统能够从经验中学习并改进,而无需进行明确的编程。机器学习算法分析和解释数据,然后使用该数据来做出预测或决策,随着时间的推移,它们会变得更加准…...
2024-08-05升级问题:Android中ScrollView嵌套listview并解决listview显示问题
问题: 当ScrollView嵌套ListView时,ListView的高度设置为wrap_content时出现ListView的高度不能完全展开,而只显示的第一个Item。 解决方法: 按item的个数乘以高度计算出listview的总高度,并在数据变化时直接设置lis…...
【热度文章】Java设计模式之中介者模 式
ava 中的中介者模式 中介者模式(Mediator Pattern)是一种行为型设计模式,它通过一个中介对象来封装一系列对象之间的交互,使这些对象之间不需要显式地相互引用,从而降低了对象之间的耦合度。 中介者模式的主要角色&…...
【3.0】vue3语法
【3】vue3语法 【一】vue前提 【1】定义变量 # 1 const是常量--》不允许变的 # 2 咱们用 ref包裹后,是个对象,虽然对象是常量,对象不能变,对象.value可以变化 # 3 之所以定义成const原因是,后期不能修改对象 【对象.…...

Navicat Monitor 荣获 2024 年 DBTA “最佳数据库性能解决方案”读者选择奖
近期,Navicat 以其卓越的服务器监控与深度分析能力在众多杰出竞争者中脱颖而出,其监控产品 Navicat Monitor 荣获了 2024 年度 DBTA 读者选择奖中的“最佳数据库性能解决方案”殊荣。该奖项不仅是对 Navicat Monitor 在数据库监控与分析领域非凡实力的权…...

[论文笔记]ZeRO: Memory Optimizations Toward Training Trillion Parameter Models
引言 今天带来ZeRO: Memory Optimizations Toward Training Trillion Parameter Models的论文笔记。 大型深度模型提供了显著的准确性提升,但训练数十亿到数万亿个参数是具有挑战性的。现有的解决方案,如数据并行和模型并行,存在基本的局限…...

shuashuashua
CVE-2023-2130 靶标介绍: 在SourceCodester采购订单管理系统1.0中发现了一项被分类为关键的漏洞。受影响的是组件GET参数处理器的文件/admin/suppliers/view_details.php中的一个未知函数。对参数id的操纵导致了SQL注入。可以远程发起攻击。 通过标靶介绍可以知道…...

k8s之HPA
目录 1.HPA 2.部署 metrics-server 3.部署 HPA 4.总结 1.HPA HPA(Horizontal Pod Autoscaling)Pod 水平自动伸缩,Kubernetes 有一个 HPA 的资源,HPA 可以根据 CPU 利用率自动伸缩一个 Replication Controller、 Deployment 或…...

fun状态上传,并可手动控制
文章目录 引言上传原因:矛盾点:基础工程源码: 代码实操fun状态上传fun状态下发控制 引言 上传原因: 续上一节, 我们把fun像小灯一样, 加入了预警工程, 但是我们fun其实还有其他用处, 比如我们人工手动开风扇, 排风, 所以我们需要把fun的状态上传, 然后也可以通过服务器手动控制…...

【Canvas与艺术】四扇叶结
注意:此是一个看起来简单,实际上需要细细计算调整的拓扑图。 【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head&…...

基于DVWA-Brute Force(LowMedium)的渗透测试
Brute force主要是通过爆破达到渗透目的: Low 查看源代码: <?phpif( isset( $_GET[ Login ] ) ) {// Get username$user $_GET[ username ];// Get password$pass $_GET[ password ];$pass md5( $pass );// Check the database$query "SE…...
水库大坝安全预警系统的作用
“汛情就是命令,防汛就是责任”,为了防治和减轻洪涝带来的危害,需要一种以预警为先导的临灾位移监测系统--水库大坝安全预警系统,对可能会出现的灾害进行实时远程监控,尽可能做到隐患早发现、早决策、早治理࿰…...

容器化部署ES集群
文章目录 一、ElasticSearch基本概念1、索引(Index)2、文档(Document)3、分片和副本4、映射(Mapping) 二、容器部署ElasticSearch集群三、容器部署ElasticSearch伪集群 一、ElasticSearch基本概念 1、索引(Index) 在ElasticSearch中,索引是文档的集合,类…...

使用排名前三的华为解锁工具来绕过忘记的华为锁屏密码
如果您在未使用“设置”应用的情况下将华为手机恢复出厂设置,同时启用了出厂重置保护 (FRP) 安全功能,您的华为设备将卡在帐户验证界面。您可以使用帐户凭据轻松绕过此锁定。但是,假设您无法回忆起旧的帐户信息。在这种情况下,您应…...

战神之父和前暴雪总裁都很期待《黑神话》:太酷想玩
近日《战神》之父David Jaffe在油管上发布视频,分享了他对《黑神话:悟空》的看法。他表示自己一直很关注这款游戏,该作的最终预告画面让他惊讶。而战斗部分更是让他大呼:“OMG”。 David Jaffe表示:“我必须要购买《黑…...
用户体验的优化:观测云在用户行为分析中的应用
在数字化商业环境中,用户体验的质量直接影响到品牌形象和客户忠诚度。观测云平台,作为一款专业的数据监控和分析工具,为企业提供了一个全面的解决方案,以深入分析用户行为并优化用户体验。 观测云的核心优势在于其能够实时处理和…...

ModelScope 部署 Flux 模型
Flux 文生图模型,是 Black Forest Labs 最近发布的模型,图片生成清晰度很高,模型可以在 ModelScope 上进行下载,本文将在本地环境中部署 Flex。使用环境如下 2080 TI 22GUbuntu 22Amd R7 2700 / 128G 启动 Model Scope 容器 Mo…...

ArkTs基础语法-声明式UI-基本概念
声明式UI语法 基本概念声明式UI描述创建组件无参数有参数 配置属性配置事件 配置子组件 基本概念 装饰器:用于装饰类、结构、方法及变量,并赋予其特殊的含义。 例如: Entry 有该装饰器的自定义组件,可以在UIAbility中使用…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...