当前位置: 首页 > news >正文

数据结构——排序(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版本 ①思路 ②过程图示 ③思考 ④代码实现 ⑤代码解释 &#xff08;2&#xff09;挖坑法 ①思路 ②过程图示 ③思考 ④代码实现 ⑤代码解释 &#xff08;3&#xff09;lomuto前后指针 ①思路 ②过程图示 ③思考 ④代码实现 ⑤代…...

2024最新版本Python安装及开发环境配置(vscodepython)

python安装 去Python官网下载最新版本&#xff1a; 接下来请一步步按照图片操作&#xff1a; 这样子就安装完成了 测试Python安装是否成功 先打开终端 右键Windows徽标&#xff0c;点击终端 然后输入python&#xff0c;如果如下图所示&#xff0c;就说明安装成功&#xff0…...

机器学习的定义

机器学习 机器学习的定义 机器学习是人工智能的一个分支&#xff0c;它使计算机系统能够从经验中学习并改进&#xff0c;而无需进行明确的编程。机器学习算法分析和解释数据&#xff0c;然后使用该数据来做出预测或决策&#xff0c;随着时间的推移&#xff0c;它们会变得更加准…...

2024-08-05升级问题:Android中ScrollView嵌套listview并解决listview显示问题

问题&#xff1a; 当ScrollView嵌套ListView时&#xff0c;ListView的高度设置为wrap_content时出现ListView的高度不能完全展开&#xff0c;而只显示的第一个Item。 解决方法&#xff1a; 按item的个数乘以高度计算出listview的总高度&#xff0c;并在数据变化时直接设置lis…...

【热度文章】Java设计模式之中介者模 式

ava 中的中介者模式 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为型设计模式&#xff0c;它通过一个中介对象来封装一系列对象之间的交互&#xff0c;使这些对象之间不需要显式地相互引用&#xff0c;从而降低了对象之间的耦合度。 中介者模式的主要角色&…...

【3.0】vue3语法

【3】vue3语法 【一】vue前提 【1】定义变量 # 1 const是常量--》不允许变的 # 2 咱们用 ref包裹后&#xff0c;是个对象&#xff0c;虽然对象是常量&#xff0c;对象不能变&#xff0c;对象.value可以变化 # 3 之所以定义成const原因是&#xff0c;后期不能修改对象 【对象.…...

Navicat Monitor 荣获 2024 年 DBTA “最佳数据库性能解决方案”读者选择奖

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

[论文笔记]ZeRO: Memory Optimizations Toward Training Trillion Parameter Models

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

shuashuashua

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

k8s之HPA

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

fun状态上传,并可手动控制

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

【Canvas与艺术】四扇叶结

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

基于DVWA-Brute Force(LowMedium)的渗透测试

Brute force主要是通过爆破达到渗透目的&#xff1a; Low 查看源代码&#xff1a; <?phpif( isset( $_GET[ Login ] ) ) {// Get username$user $_GET[ username ];// Get password$pass $_GET[ password ];$pass md5( $pass );// Check the database$query "SE…...

水库大坝安全预警系统的作用

“汛情就是命令&#xff0c;防汛就是责任”&#xff0c;为了防治和减轻洪涝带来的危害&#xff0c;需要一种以预警为先导的临灾位移监测系统--水库大坝安全预警系统&#xff0c;对可能会出现的灾害进行实时远程监控&#xff0c;尽可能做到隐患早发现、早决策、早治理&#xff0…...

容器化部署ES集群

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

使用排名前三的华为解锁工具来绕过忘记的华为锁屏密码

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

战神之父和前暴雪总裁都很期待《黑神话》:太酷想玩

近日《战神》之父David Jaffe在油管上发布视频&#xff0c;分享了他对《黑神话&#xff1a;悟空》的看法。他表示自己一直很关注这款游戏&#xff0c;该作的最终预告画面让他惊讶。而战斗部分更是让他大呼&#xff1a;“OMG”。 David Jaffe表示&#xff1a;“我必须要购买《黑…...

用户体验的优化:观测云在用户行为分析中的应用

在数字化商业环境中&#xff0c;用户体验的质量直接影响到品牌形象和客户忠诚度。观测云平台&#xff0c;作为一款专业的数据监控和分析工具&#xff0c;为企业提供了一个全面的解决方案&#xff0c;以深入分析用户行为并优化用户体验。 观测云的核心优势在于其能够实时处理和…...

ModelScope 部署 Flux 模型

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

ArkTs基础语法-声明式UI-基本概念

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

LAV Filters:解码Windows媒体播放困境的开源解决方案

LAV Filters&#xff1a;解码Windows媒体播放困境的开源解决方案 【免费下载链接】LAVFilters LAV Filters - Open-Source DirectShow Media Splitter and Decoders 项目地址: https://gitcode.com/gh_mirrors/la/LAVFilters 如何突破Windows媒体播放的格式壁垒 在2010…...

Qwen3.5-4B-Claude-Opus惊艳效果展示:分步骤推导二分查找O(log n)全过程

Qwen3.5-4B-Claude-Opus惊艳效果展示&#xff1a;分步骤推导二分查找O(log n)全过程 1. 模型能力概览 Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF是一个专为推理任务优化的轻量级模型&#xff0c;特别擅长处理需要分步骤分析的技术问题。这个4B参数的模型通过蒸馏…...

医疗工作者的AI助手:MedGemma在症状鉴别诊断中的实战应用

医疗工作者的AI助手&#xff1a;MedGemma在症状鉴别诊断中的实战应用 1. 医疗AI的新范式&#xff1a;透明化诊断推理 在繁忙的临床工作中&#xff0c;医生们常常面临这样的挑战&#xff1a;如何在有限时间内准确识别症状组合背后的病因&#xff1f;传统方法依赖个人经验记忆和…...

【shell编程】深入解析Permission denied:7种实战解决方案与场景应用

1. 为什么会出现Permission denied错误&#xff1f; 第一次在终端里看到"Permission denied"这个红色警告时&#xff0c;我正试图运行一个刚写好的shell脚本。当时完全懵了&#xff0c;明明文件就在那里&#xff0c;为什么说没权限&#xff1f;后来才发现&#xff0c…...

springboot-vue+nodejs的旅游服务管理系统

目录技术栈选择系统模块设计开发流程部署方案关键注意事项项目技术支持源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作技术栈选择 后端框架&#xff1a;Spring Boot&#xff08;Java&#xff09;用于业务逻辑、数据管理及API提供。前端框架…...

腾讯混元翻译模型惊艳展示:HY-MT1.5-1.8B多语言翻译案例集

腾讯混元翻译模型惊艳展示&#xff1a;HY-MT1.5-1.8B多语言翻译案例集 1. 引言&#xff1a;当翻译遇见大模型&#xff0c;语言不再是障碍 想象一下&#xff0c;你正在阅读一篇最新的科技论文&#xff0c;原文是英文&#xff0c;但你的母语是中文。或者&#xff0c;你收到一封…...

量子力学的抽象地位与c语言等价

多种量子/粒子的各种表象&#xff0c;就像 cpu 的微架构指令集&#xff0c;量子力学的状态矢量表示和密度矩阵表示就像c语言。 中间从状态矢量到具体粒子的具体表象的转换&#xff0c;就像是一个编译器的工作。量子力学表象与编译器架构的深刻类比这个类比非常精妙且深刻&#…...

手机号查询QQ技术解析与实战指南

手机号查询QQ技术解析与实战指南 【免费下载链接】phone2qq 项目地址: https://gitcode.com/gh_mirrors/ph/phone2qq 问题&#xff1a;数字化时代的身份关联困境 在现代社会&#xff0c;手机号与QQ号作为重要的数字身份标识&#xff0c;其关联查询需求日益凸显。当用户…...

C++的std--ranges适配器视图与惰性求值在无限序列中的潜在应用

C的std::ranges适配器视图与惰性求值在无限序列中的潜在应用 现代C通过引入std::ranges库&#xff0c;为序列操作带来了更简洁、高效的编程范式。其中&#xff0c;适配器视图与惰性求值的结合&#xff0c;为处理无限序列提供了全新的可能性。这种技术不仅能够避免不必要的计算…...

Z-Image-Turbo-rinaiqiao-huiyewunv 模型文件瘦身与加速技巧:Pruning 与 Quantization 初探

Z-Image-Turbo-rinaiqiao-huiyewunv 模型文件瘦身与加速技巧&#xff1a;Pruning 与 Quantization 初探 你是不是也遇到过这样的情况&#xff1a;好不容易找到一个效果惊艳的AI图像生成模型&#xff0c;比如Z-Image-Turbo-rinaiqiao-huiyewunv&#xff0c;兴冲冲地准备部署&am…...