快排详解(4种写法:霍尔/挖坑法/双指针/非递归)

//本文所写快排的结果都是从小到大排序

思路

快排就是把数组的第一个值记为key,然后定义两个指针,一个叫begin,一个叫end.

begin指针从数组的头部出发,寻找比key大的值;end指针从数组的尾部出发,寻找比key小的值;

然后交换begin和end的值

......最后,begin和end相遇就停下,此时交换begin和key的值(也可以看做交换end和key的值),

就可以得到这样的结果:key左边的值都比key小,key右边的值都比key大.

然后key的左边和右边分别进行上面的排序过程,直到数组彻底有序为止.

待会还有一些细节的东西会在下面提到.

图解

比较简略,大家将就着看叭...

图中的left和right指针就是上面提到的begin和end指针...

3d5a89f9c60c4aceb7b6d8c05d5d5aae.png

霍尔版本写法(递归)

代码有两个函数,一个是QuickSort,构建了递归的框架;另一个是_QuickSort,里面写了快排的排序实现.

int _QuickSort(int* a, int left,int right)
{int key = left;int begin = left;int end = right;while (begin < end){//end先走,end找比key小的值while (begin < end && a[end] >= a[key])//防止越界,加上begin < end{--end;}//begin找比key大的值while (begin < end && a[begin] <= a[key]){++begin;}swap(a[begin], a[end]);}swap(a[key], a[begin]);
//注意:我们交换的是数组的a[key]和 a[begin],但是key等于left,key应该更新成beginkey = begin;return key;
}void QuickSort(int* p, int left, int right)
{if (left >= right){return;}else{int key = _QuickSort(p, left, right);QuickSort(p, left, key - 1);QuickSort(p, key + 1, right);}}

注意事项

1.关于end先走

end先走可以保证最终停留的位置比key小。(不考虑这种情况:在数组有序的情况下,第一次循环end直接走到begin的位置,此时key位置的值就会等于end/begin位置的值)

让我们分析循环终止的情况:

要么就是end--走到了begin的位置,begin位置的值比key小,因为begin还在上次交换的位置,begin存的是比key小的值。

要么是end找到了比key小的值,就停在了那里,begin走到了end的位置,begin存的值也会比key小。

2.end先走的作用

交换key和begin的值,要保证key的左边值都比key小,右边值都比key大,所以begin停留的位置(换而言之end停留的位置)要比key小,才能做到。

优化

1.key值的选取

万一key值是最小的或者最大的,走快排就很浪费时间,所以我们选的key最好是一个中间值.

所以我们将会写一段代码来选取合适的key值.

2.数据比较少的时候使用插入排序

当数据个数比较少的时候,走插入排序比快排快,所以假设有百万数据时,我们可以让数据小于10个的时候走插入排序,数据大于10个走插入排序

3.优化后的代码

//此代码的swap函数是库里的

//为key选取合适的中间值
int GetMidi(int* a, int left, int right)
{int midi = left + (right - left) / 2;if (a[left] >= a[midi]){if (a[right] >= a[left]) {return left;}else if (a[midi] >= a[right]){return midi;}else{return right;}}else{if (a[left] >= a[right]){return left;}else if (a[midi] <= a[right]){return midi;}else{return right;}}
}void InsertSort(int* a, int n)
{for (int i = 0; i < n - 1; i++){int end = i;int temp = a[end + 1];while (end >= 0){if (a[end] > temp){a[end + 1] = a[end];--end;}else{break;}}a[end + 1] = temp;}
}int _QuickSort(int* a, int left,int right)
{int midi = GetMidi(a, left, right);if (midi!=left){swap(&a[midi], &a[left]);}int keyi = left;int begin = left;int end = right;while (begin < end){//end先走,end找比key小的值while (begin < end && a[end] >= a[key])//防止越界,加上begin < end{--end;}//begin找比key大的值while (begin < end && a[begin] <= a[key]){++begin;}swap(a[begin], a[end]);}swap(a[key], a[begin]);key = begin;return key;
}

挖坑法(递归)

挖坑法在效率上和霍尔法一样,但是会少很多注意事项.

思路

大体上和霍尔排序的思路一样,也有两个指针left和right从头和尾出发,一个找比key大,一个找比key小.

区别在于选取了key值之后,原数组key的地方会空出来,等待比key 小的值right放进去,然后数组里就会空出right的位置,等待比key大的值left放进right的位置,然后left的位置会空出来.......重复此过程,直到left和right相遇.

图解

代码

//此代码的swap是自己写的


void InsertSort(int* arr, int n)
{for (int i = 0; i < n - 1; i++){int end = i;int temp = arr[end + 1];while (end >= 0){if (temp < arr[end]){arr[end + 1] = arr[end];end--;}else{break;}}arr[end + 1] = temp;}
}int GetMid(int* arr, int left, int right)
{int mid = (left + right) / 2;if (arr[left] <= arr[mid]){if (arr[left]>=arr[right]){return left;}else if (arr[mid]<=arr[right]){return mid;}else{return right;}}else{if (arr[mid]>arr[right]){return mid;}else if (arr[left]<arr[right]){return left;}else{return right;}}
}void swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}void QuickSort(int* arr, int left,int right)
{if (left >= right) {return;}if ((right - left + 1)<=10){InsertSort(arr + left, right - left + 1);return;}else{int mid = GetMid(arr, left, right);if (mid != left){swap(&arr[mid], &arr[left]);}int key = arr[left];//int flag = 0;int lefti = left, righti = right;
//首次记录hole的值int hole = left;while (lefti < righti){while (lefti < righti && arr[righti] >= key){--righti;}
//比key小的值填入holearr[hole] = arr[righti];
//更新hole的位置hole = righti;while (lefti < righti && arr[lefti] <= key){++lefti;}
//比key大的值填入holearr[hole] = arr[lefti];
//更新hole的位置hole = lefti;}arr[hole] = key;QuickSort(arr, left, hole - 1);QuickSort(arr, hole + 1, right);}}

双指针法

思路

有两个指针,一个叫pre,一个叫cur,

cur初始时在pre前面的一个位置,

每循环一次,cur都会往前走一步,

如果cur的值比key小,且pre的下一个值不等于cur,

(实际上,如果cur的值比key大,pre指针就不会走)

那就交换cur和pre的值.

图解

代码

//GetMidi函数本文前面出现过,我就不放了
int partSort2(int* a, int left, int right)
{int midi = GetMidi(a, left, right);if (midi != left){swap(&a[midi], &a[left]);}int keyi = left;int prev = left;int cur = prev + 1;while (cur <= right){while (a[cur] < a[keyi] && ++prev != cur){swap(&a[cur], &a[prev]);}++cur;}swap(&a[keyi], &a[prev]);return prev;
}
//QuickSort函数也要调用哦,本文前面出现过我就不放了

非递归(使用栈)

思路

和递归的部分思路是相似的,

同样需要key值,

key把数组分为左右两部分,

右边数组先入栈,

左边数组后入栈,

每次取栈顶的区间排序.

代码

void QuickSortNonR(int* a, int left, int right)
{stack<int> st;st.push(left);st.push(right);while (!st.empty()){int end = st.top();st.pop();int begin = st.top();st.pop();
//这是双指针法排序,在本文章的上一部分提及了int key = partSort2(a, begin, end);if (key + 1 < end) {st.push(key + 1);st.push(end);}if (begin < key - 1){st.push(begin);st.push(key - 1);}}
}

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

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

相关文章

ESP32驱动PCM5102A播放SD卡音频

文章目录 简介模块参数功能框图引脚定义通信接口和通信数据格式通信流程引脚接线ESP32和PCM5102AESP32和SD模块 主要代码spi.hSD.hAudio.h实验效果总结 简介 PCM5102A模块是一款立体声DAC模块、音频数模转换器&#xff0c;内部集成了PCM5102芯片。PCM5102芯片是集成了立体声模…

ProtonBase 教育行业解决方案

01/方案概述 当前&#xff0c;大数据、云计算等技术正加速教育行业的数字化转型&#xff0c;教学模式从线下转向线上&#xff0c;传统教育企业向具有互联网性质的新型教育企业转变。在此背景下&#xff0c;教育企业亟需探索多源数据的融合扩展&#xff0c;以应对复杂的业务场景…

2025年人工智能,自动化与机械工程国际学术会议(AIAME2025)

早鸟通道开启&#xff1a; 2025年人工智能&#xff0c;自动化与机械工程国际学术会议&#xff08;AIAME2025&#xff09; 2025 International Conference on Artificial Intelligence, Automation, and Mechanical Engineering 【重要日期】 早鸟征稿截止日期&#xff1a;…

C++ STL 容器系列(三)list —— 编程世界的万能胶,数据结构中的百变精灵

STL系列学习参考&#xff1a; C STL系列__zwy的博客-CSDN博客https://blog.csdn.net/bite_zwy/category_12838593.html 学习C STL的三个境界&#xff0c;会用&#xff0c;明理&#xff0c;能扩展&#xff0c;STL中的所有容器都遵循这个规律&#xff0c;下面我们就按照这三个境…

【AI技术赋能有限元分析应用实践】Abaqus有限元分析到深度学习方法应用全过程——汽车刹车片热力耦合分析

目录 一、项目实现介绍**项目背景****项目目标****项目流程概述****技术融合****项目价值** 二、实现流程**Step 1: 分析问题构建方法&#xff0c;寻找主要分析目标&#xff0c;确定初步目标****Step 2: 使用 Abaqus 完成有限元仿真&#xff0c;后处理并保存数据为 odb 格式***…

从0开始linux(38)——线程(1)线程概念

欢迎来到博主专栏&#xff1a;从0开始linux 博主ID&#xff1a;代码小豪 文章目录 进程与线程线程概念线程的优点线程的独立数据 进程与线程 如果要理解线程&#xff0c;那么进程将会时绕不开的点。首先我们回顾一下我们之前在进程章节当中是如何描述进程的&#xff1f; 进程&…

Doge东哥wordpress主题

Doge东哥wordpress主题是一款专为中小型企业设计的WordPress外贸网站模板&#xff0c;它以其现代、专业且用户友好的界面&#xff0c;为企业提供了一个展示产品和服务的理想平台。以下是对该模板的详细描述&#xff1a; 首页设计概览 首页的设计简洁而不失大气&#xff0c;顶…

keil 5. Flash Timeout. Reset the Target and try it again.

使用官方STM32 ST-LINK Utility 烧写软件 KEIL 5, 设置DFP 包支持FLASH烧写算法 Keil 5, Flash Timeout. Reset the Target and try it again.-CSDN博客

MySQL源码编译

华子目录 下载源码包上传并解压安装cmake环境检测make编译make install安装 部署 下载源码包 下载相应源码包mysql5.7编译安装需要boost库&#xff0c;这里官网下载含boost的源码包https://downloads.mysql.com/archives/community/ 上传并解压 [rootmysql-node1 ~]# du -sh …

【Canvas与化学】枣红实心球钙元素图标

【成图】 120*120 大小图 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>钙元素图标 Draft2</title><style type&qu…

YOLOv8实战无人机视角目标检测

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对无人机目标数据集进行训练和优化&#xff0c;该数据集包含丰富的无人机目标图像…

私有库gitea安装

一 gitea是什么 Gitea是一款自助Git服务&#xff0c;简单来说&#xff0c;就是可以一个私有的github。 搭建很容易。 Gitea依赖于Git。 类似Gitea的还有GitHub、Gitee、GitLab等。 以下是安装步骤。 二 安装sqilite 参考&#xff1a; 在windows上安装sqlite 三 安装git…

【Anaconda】 创建环境报错:CondaHTTPError: HTTP 000 CONNECTION FAILED for url

问题描述 使用 Anaconda 创建环境时报错&#xff1a; CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com/pkgs/free/noarch/repodata.json.bz2> Elapsed: -An HTTP error occurred when trying to retrieve this URL. HTTP errors are o…

十一、快速入门go语言之接口和反射

文章目录 接口:one: 接口基础:two: 接口类型断言和空接口:star2: 空接口实现存储不同数据类型的切片/数组:star2: 复制切片到空接口切片:star2: 类型断言 反射 &#x1f4c5; 2024年5月9日 &#x1f4e6; 使用版本为1.21.5 接口 十、Java类的封装和继承、多态 - 七点半的菜市…

计算机的错误计算(一百七十)

摘要 回复一中学生来信&#xff0c;探讨 MATLAB 关于算式 的计算问题。 在计算机的错误计算&#xff08;一百三十二&#xff09;中&#xff0c;我们探讨了手持式计算器关于算式 的计算问题。一中学生来信询问该算式在数学软件中是否会出错。 例1. 在 MATLAB 中计算 . 首…

【科研】9如何高效阅读和理解学术论文

【科研】9如何高效阅读和理解学术论文 写在最前面一、为什么需要系统的阅读方法&#xff1f;二、阅读论文的11步方法三、实践示例四、常见问题解答五、结语 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光&#xff0c;感谢你的陪伴与支持 ~ …

RabbitMQ在手动消费的模式下设置失败重新投递策略

最近在写RabbitMQ的消费者&#xff0c;因为业务需求&#xff0c;希望失败后重试一定次数&#xff0c;超过之后就不处理了&#xff0c;或者放入死信队列。我这里就达到重试次数后就不处理了。本来以为很简单的&#xff0c;问了kimi&#xff0c;按它的方法配置之后&#xff0c;发…

计算机毕业设计Python+卷积神经网络股票预测系统 股票推荐系统 股票可视化 股票数据分析 量化交易系统 股票爬虫 股票K线图 大数据毕业设计 AI

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

《我的世界之武艺时代》——第2话

观众朋友们&#xff0c;大家好&#xff01;欢迎来到《我的世界之武艺时代》的精彩世界。在开始这段奇幻旅程之前&#xff0c;请您花几秒钟的时间为我们的作品点个赞&#xff0c;并将其收藏到您的书架中。这不仅是对我们创作者的最大支持&#xff0c;也是让更多人发现这部作品的…

如何将 GitHub 私有仓库(private)转换为公共仓库(public)

文章目录 如何将 GitHub 私有仓库转换为公共仓库步骤 1: 登录 GitHub步骤 2: 导航到目标仓库步骤 3: 访问仓库设置步骤 4: 更改仓库可见性步骤 5: 确认更改步骤 6: 验证更改注意事项 如何将 GitHub 私有仓库转换为公共仓库 在软件开发领域&#xff0c;GitHub 是一个广受欢迎的…