快速排序详解!c语言

目录

快速排序是什么?

快速排序的三种方法!

快速排序的优化

1.hore法(初代目)

hore法的源码 

源码解析

2.挖坑法(常用)!!!!

挖坑法源码 

3.前后指针法 (常用)

前后指针代码

4.非递归法 

 快速排序全过程图


快速排序是什么?

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法
快速排序顾名思义,快速的排序,事实也如此,他的应用面广泛同时确实很快,因为他的时间复杂度是o(nlogn),相比前面的(插入冒泡选择)三小只来说,它的速度确实遥遥领先,但相对的思想也更复杂。

它的主要思想白话来说,就是

1.选择一个数据mid(中间人),以他为基准,

2.将剩下的数据比他小的放在左边,比他大的放在右边,

就像你开了一个宴会聘请四方,不止来了老一辈的投资人,还有新时代的年轻创业者们,因为有代沟自然分为了两边,而你就是中间那个负责笼络介绍的。但这个只是第一步(之后还要重复这一步)。下面的三种方法会详细解析全步骤。

快速排序的三种方法!

快速排序的优化

因为我们要找到中间值所以可以采用三数取中的算法,就是从第一个 和 中间值 和 最后一个数据中选择三个数字的中间值。

解释:如果一个数组是有序的,1 2 3 4 5 6 7 8 9 10.这时候如果还是取1 为中间值,那就会导致最开始的分组就没有比1 小的数字,这样一组一组的往下走,时间一定特别久。所以如果用三数取中 取到 5那就不会出现这种情况了。

1.hore法(初代目)

第一层:原理

  初代目的方法就是,以数组的第一个值作为中间人mid(key),通过和这个中间人比较大小,分出两边,就如上面说的投资派,和创业派。

  但你发现这也没有序啊,之后分为两边后,然后在继续划分,取左边的第一个数字作为中间人,然后再分为两边,分到只剩下一个数据后,开始返回。最终返回一个有序的数组。右边也是同理,然后把左右和一开始的中间人组合起来就是一个有序的数组。

第二层:如何交换数据(关键)

查找过程先从后面开始遍历找到一个比key中间值小的数字,然后再从第二个数据开始遍历找到一个大于key的数字,然后交换数字,直到L和R相遇一趟排序结束。

第三层:为什么end(right)先走。

为什么要从right开始,因为你的key在数组的第一个位置,所以最后一次和key交换的数据一定要是比key小的。

如果left(begin)先走,如果只有最后一个数字比key大这时begin 和 end 相遇,反而把key换到了最后一个位置,而唯一比key大的数字反而去了第一个,那就不满足,左小右大的原则了

 

hore法的源码 
int PartSort1(int* arr, int left, int right)
{int key = left;		//使用key保存基准值下标while (left < right){while (left < right && arr[key] <= arr[right])	//只找小的,等于要过滤,找前判断right有没有走过{right--;}while (left < right && arr[key] >= arr[left]){left++;}if (left < right)	//没有相遇时左右交换{Swap(&arr[left], &arr[right]);}}Swap(&arr[key], &arr[left]);	//交换基准值和相遇位置的值,并返回基准值的下标return left;
}
void QuickSort(int* a, int left, int right)
{if (left >= right){return;}int key = PartSort1(a, left, right);QuickSort(a, left, key - 1);QuickSort(a, key + 1, right);
}
源码解析

 先用三数取中取到中间数。begin  < end 即相遇停止,为什么第二个第三个while中也有begin < end 呢?是为了防止end 或者 begin 相遇后继续往前走。

第二个条件就是找大找小,然后再把找到的大小交换。直到begin 和 end 相遇。

最后交换第一个数字和二者(begin 和 end)相遇的位置。

同时记得交换其中的值。

如果只交换了值没有把位置交换,就会导致key还是在 下标为 0 的位置,接下来在递归时出错。

因为快排不是单趟而是要分大小组。所以这个递归很像二叉树的前序遍历,从左边小的开始(当然也可以从大的开始)先把一边排序好,再排另一边。

但对于hore初代目法来说,因为它里面的坑太多就导致一般不用它,而是后面的两种方法 

2.挖坑法(常用)!!!!

挖坑法如名字一样:

第一步:挖坑,进墓

将第一个数字给挖出来用一个槽子装着(将其赋值给一个临时变量)这个值我们叫做key

以它作为探宝仪

第二步:寻宝,弃杂物。

这里我把大于key的值比作宝,把小于key的值比作杂物。

目前面前有10个物品,你站在右边从最后一个物品开始测试,前两个 8 10 大于key,那就摆着不动找到一个质量低于6,将它放在刚刚取走探宝仪的地方。现在高质量这边就少了一个了

可是我又是一个强迫症

于是我返回左边,又开始找质量大于6的。走了两步找到一个质量7的,我就把它摆在刚刚缺的位置。

就这样重复直到左右都找完了找到最后一个肯定是小于6的(上一个解法的最后有解释)。将他们进行交换。

这样第一趟就结束了,但我发现好像每个位置都是有个标号而且还是排序好的。强迫症的我,继续用这样的方式,将大小分边,直到两边都排好序。最后排好后,密室打开了。恭喜你解锁快排。

置于为什么这个是常用的呢?因为hore法的坑太多,所以常用的是这个。

挖坑法源码 
int PartSort(int* arr, int left, int right)
{int key = arr[left];int hole = left;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;
}

 1.取key值。

2.循环条件和之前一样;直到二者相遇,相遇后不改变。找大找小。

3.每次交换后更换坑(hole)的位置。

4.最后的坑位就是二者相遇的位置。这个坑的位置填上key即可。返回每次的坑位。

3.前后指针法 (常用)

1.前后指针法:

还是和挖坑法一样,前后指针还是盗慕,不过这次带了一个跟班。

这里prev 为跟班 而 cur 就是我。

宝藏开启的钥匙key现在等于6,现在要做的就是找到小于key和大于key的开门条件。

cur负责在前面走,找到大的话cur就继续走,这时prev不动。直到我找到一个小的,

我让prev向前走一步,如何我把小的开门条件扔给prev,让他装上,然后他把他脚下的大的开门条件扔给我,我在装上(这里相当于prev和cur上的值交换)。tips:因为cur之前走到大的时候没让prev动,所以prev的下一步只有两种情况(1.是大的开门条件2.cur的上一步)

如何我继续往前找小,每次找到小就让prev往前走,让其把小的开门条件装上去。我再把大的开门条件装上去,这样直到我走完,这时prev还是在最后一个小的开门条件上。这时把key和prev交换(因为第一个位置的小开门条件还没装上),就可以把大于key和小于key的值分开了。最后将prev位置上的拿回去装上,再把key拿过来开门,就解决了。

2.快速排序:

我们现在把门打开了,发现还是不行,现在不再是一排,而是分成了两排。

其中每一排的数量刚好等于刚刚大于key的开门条件和小于key的开门条件的数量。

我也反应过来这是要再按刚刚的方法在进行一次。就这样无限套娃。

直到全部有序。才拿到宝物。

前后指针代码
int PartSort(int* arr, int left, int right)
{int key = left;int prev = left;int cur = left + 1;while (cur <= right){//arr[cur]小于基准值就交换if (arr[cur] <= arr[key] && ++prev != cur)	//这里做了优化:如果prev+1等于cur则不用交换,该语句顺便将prev加一{Swap(&arr[cur], &arr[prev]);}cur++;}Swap(&arr[key], &arr[prev]);return prev;
}

4.非递归法 

非递归法需要用到栈来实现。 

void QuickSort(int* arr, int begin, int end)
{//创建栈并压入数组区间Stack *ps = NULL;StackInit(&ps);StackPush(ps, begin);StackPush(ps, end);while (!StackEmpty(ps)){//从栈中获取左右区间int right = StackTop(ps);StackPop(ps);int left = StackTop(ps);StackPop(ps);//判断左右区间是否合理,若不合理则跳过本次循环if (left >= right){continue;}//执行单趟排序并获取基准值下标int key = PartSort(arr, left, right);//将基准值分割的两个区间压入栈中StackPush(ps, left);StackPush(ps, key-1);StackPush(ps, key+1);StackPush(ps, right);}StackDestroy(&ps);
}

 

非递归:

就是用栈模拟递归的过程,每次压进去的都是区间的范围,通过区间范围,对这个区间再次进行partsort。

 快速排序全过程图

快速排序需要一层层拨开,拨到只剩最后一个才能组合起来。因为排序的时候,已经把位置都交换好了,递归回去时排序就完成了。

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

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

相关文章

springboot快鞋屋系统-计算机毕业设计源码06912

摘 要 如今&#xff0c;人们的消费水平和购物能力都大大提升&#xff0c;加上互联网技术日新月异的发展&#xff0c;电子商务这种新兴的商业模式&#xff0c;在短短几年里已经开始融入中国社会&#xff0c;成为家哈户晓的热门话题&#xff0c;在网上购物已经成为一种潮流&#…

键盘输入4个数,从小到大排序

题目 键盘输入4个整数&#xff0c;从小到大排序 思路 代码 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h>//键盘输入4个整数&#xff0c;从小到大排序 int main() {int n1, n2, n3, n4;scanf_s("%d %d %d %d", &n1, &n2, &n3, &n4);…

基于Java开发的个人视频网站的搭建与实现[附源码]

基于Java开发的个人视频网站的搭建与实现[附源码] &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系统 &am…

网工内推 | 外企网工、售前,最高15K*13薪,厂商认证优先

01 广州群欣软管有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责公司计算机及办公设备的软、硬件日常维护&#xff1b; 2、负责公司erp系统、监控系统及网站的管理维护&#xff1b; 3、负责根据公司发展战略方向及业务规划&#xff0c;制定公司信息化的…

ST32——点亮第一盏灯

环境搭建 项目模板搭建 main函数 电路图 代码示例 #include "gd32f4xx.h" #include "systick.h" #include <stdio.h> #include "main.h"/** LED硬件对应关系 LED1 PE3 LED2 PD7 LED3 PG3 LED4 PA5点亮LED1 **/int main(void) {systick_…

【Linux】---Linux下基本指令(2)

目录 一、指令详细介绍1.1 cat 指令1.2 echo 指令1.3 more 指令1.4 less 指令1.5 head 指令1.6 tail 指令1.7 date 指令1.8 cal 指令1.9 find 指令1.10 grep 指令1.11 zip/unzip 指令1.12 tar 指令1.13 uname –r 指令&#xff1a; 一、指令详细介绍 1.1 cat 指令 语法&#…

每日汇评:黄金有望在复苏之路上重新夺回关键的2025美元关口

周一&#xff0c;金价在本周初延续了其复苏模式&#xff1b; 随着投资者重新评估美联储降息押注&#xff0c;美元跟随美债收益率走软&#xff1b; 黄金买家需要突破21日移动均线2025美元,RSI指数稳定在50以下&#xff1b; 随着买家将上周的复苏模式延续到周一&#xff0c;黄金价…

三防工业平板丨亿道加固平板定制丨三防平板电脑丨提升后勤管理

企业的后勤管理对于运作高效的商业模式至关重要。随着科技的不断发展&#xff0c;加固平板成为提升企业后勤水平的一项关键措施。本文将探讨加固平板在企业后勤管理中的应用和优势&#xff0c;并阐述如何利用这一技术提升企业的运营效率和竞争力。 一、三防加固平板的定义和功能…

云手机受欢迎背后的原因及未来展望

随着办公模式的演变&#xff0c;云手机的热潮迅速兴起。在各种办公领域&#xff0c;云手机正展现出卓越的实际应用效果。近年来&#xff0c;跨境电商行业迎来了蓬勃发展&#xff0c;其与国内电商的差异不仅体现在整体环境上&#xff0c;更在具体的操作层面呈现出独特之处。海外…

python----面向对象

这里写目录标题 面向对象思想类类的定义类名的定义类的构造函数的定义类的属性类的方法定义 继承语法关于构造函数问题 文件操作绝对路径相对路径pycharm获取绝对路径和相对路径文件读写读文件open&#xff08;&#xff09;read&#xff08;&#xff09;readline&#xff08;&a…

Python(九十三)函数的参数总结

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

网站常见的反爬手段及反反爬思路

摘要:介绍常见的反爬手段和反反爬思路&#xff0c;内容详细具体&#xff0c;明晰解释每一步&#xff0c;非常适合小白和初学者学习&#xff01;&#xff01;&#xff01; 目录 一、明确几个概念 二、常见的反爬手段及反反爬思路 1、检测user-agent 2、ip 访问频率的限制 …

Stochastic Depth 原理与代码解析

paper&#xff1a;Deep Networks with Stochastic Depth official implementation&#xff1a;https://github.com/yueatsprograms/Stochastic_Depth third-party implementation&#xff1a;https://github.com/open-mmlab/mmcv/blob/main/mmcv/cnn/bricks/drop.py 存在的问…

【day01】每天三道 java后端面试题:JDK、JRE和JVM | 字节码 | ACID

文章目录 1. JDK, JRE, JVM分别是什么&#xff1f;有什么区别&#xff1f;2. 什么是字节码&#xff1f;采用字节码的最大好处是什么&#xff1f;3. 什么是数据库事务&#xff1f;讲一下事务的ACID特性。 1. JDK, JRE, JVM分别是什么&#xff1f;有什么区别&#xff1f; 答题思路…

深度解析 Transformer 模型:原理、应用与实践指南【收藏版】

深度解析 Transformer 模型&#xff1a;原理、应用与实践指南 1. Transformer 模型的背景与引言2. Transformer 模型的原理解析2.1 自注意力机制&#xff08;Self-Attention&#xff09;自注意力机制原理 2.2 多头注意力机制&#xff08;Multi-Head Attention&#xff09;多头注…

java+vue_springboot企业设备安全信息系统14jbc

企业防爆安全信息系统采用B/S架构&#xff0c;数据库是MySQL。网站的搭建与开发采用了先进的java进行编写&#xff0c;使用了vue框架。该系统从三个对象&#xff1a;由管理员、人员和企业来对系统进行设计构建。主要功能包括&#xff1a;个人信息修改&#xff0c;对人员管理&am…

C++ 浮点数二分 数的三次方根

给定一个浮点数 n &#xff0c;求它的三次方根。 输入格式 共一行&#xff0c;包含一个浮点数 n 。 输出格式 共一行&#xff0c;包含一个浮点数&#xff0c;表示问题的解。 注意&#xff0c;结果保留 6 位小数。 数据范围 −10000≤n≤10000 输入样例&#xff1a; 1000.00…

树与二叉树

树与二叉树 文章目录 树与二叉树一、树的概念及结构1.、树的概念2、树的相关概念1.3 树的表示 二、二叉树1.概念2、特殊的二叉树3、二叉树的性质4、二叉树的存储结构 三、二叉树的顺序结构及实现1、二叉树的顺序结构2、堆的概念及结构3、堆的实现 四、二叉树链式结构的实现1、遍…

python统计分析——一元线性回归分析

参考资料&#xff1a;用python动手学统计学 1、导入库 # 导入库 # 用于数值计算的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 用于绘图的库 import matplotlib.pyplot as plt import seaborn as sns sns.set() # 用于估计统计…

JAVA常见IO模型 BIO、NIO、AIO总结

BIO Blocking IO 同步阻塞型IO。当系统进行IO读写的时候&#xff0c;会阻塞&#xff0c;直到IO读写完毕。比如调用系统Read后&#xff0c;需要将内核空间的数据读取到用户空间。需要等待内核空间 数据准备&#xff0c;数据就绪&#xff0c;拷贝数据&#xff0c;线程一直处于阻…