快速排序(下)
快速排序(下)

前言
在上一篇文章中我们了解了快速排序算法,但那是Hoare的版本,其实还有别的版本:一种是挖坑法,它们的区别主要在于如何找基准值。霍尔的版本思路难理解但代码好理解,挖坑法则是思路好理解但代码不好理解;还有一种是lomuto的前后指针法。
此外,还有不使用递归的快排方法(找基准值还是用的三种方法之一)。
本文就来讲解这几种不同的快排方法。
正文
挖坑法
实现思路:
创建左右指针。首先从右向左找出比基准值小的数据,找到后立即放入左边坑中,当前位置变为新的“坑”,然后从左向右找出比基准值大的数据,找到后立即放入右边坑中,当前位置变为新的“坑”,结束循环后将最开始存储的分界值放入当前的“坑”中,返回当前“坑”的下标(即分界值下标)。
画图理解一下什么是“坑”。

这就是整个“挖坑”然后“填坑”直到left和right重叠时将基准值放到该位置(它该待的位置)的过程。
现在我们可以来写一下挖坑法的代码:
//挖坑法
int _QuickSort(int* arr, int left, int right)
{int hole = left;int key = arr[hole];while (left < right)//注意和霍尔版区别{//这里同样需要限制且不能是arr[right] >= key,否则可能无法“二分”,最终效率低下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;
}
排序效果
我们在main函数中写这样的代码:
int a[] = { 5, 3, 9, 6, 2, 4, 7, 1, 8 };int n = sizeof(a) / sizeof(int);printf("排序前: ");PrintArr(a, n);//代码不具体展示QuickSort(a, 0, n-1);printf("排序后: ");PrintArr(a, n);
执行结果:

可以看到我们就成功排序了。
lomuto前后指针法
实现思路:
创建前后指针,从左往右找比基准值小的进行交换,使得小的都排在基准值的左边。
其实前后指针对于很多学过数据结构的人来说应该已经不陌生了,但是快排也能用到前后指针法,我们看看具体怎么做:
- 定义两个变量prev和cur,让cur指向位置的数据和key值比较
- 若arr[cur]<arr[key],prev向后走一步并和cur交换
- 若arr[cur]>=arr[key],cur继续往后
- 退出循环后将prev与key值交换,找到基准值
同样不变的思路也是要找基准值,也就是要让基准值左侧的数据都小于基准值,让基准值右侧的数据都大于基准值。
那么两个变量的作用是什么?可以说prev是用来占坑的,而cur用来找小,找到小后就让prev加一后和cur交换。退出循环后将prev与key值交换,就找到了基准值。
代码:
//lomuto前后指针法
int _QuickSort(int* arr, int left, int right)
{int prev = left, cur = left + 1;int key = left;while (cur<=right){if (arr[cur] < arr[key] && ++prev !=cur)//prev和cur相同就不交换//写为arr[cur] <= arr[key],加上等号也是殊途同归{Swap(&arr[cur], &arr[prev]);}cur++;//进不进循环cur都要往后走}Swap(&arr[key], &arr[prev]);return prev;
}
执行效果:

也一样成功排序完了。
可以发现这一种方法比起前面的Hoare版本和挖坑法,在取不取等号的探讨上少了很多麻烦。
-
注意:
在循环内的if语句中arr[cur] < arr[key]如果写为arr[cur] <= arr[key],并不能解决无法”二分“子序列的问题,所以加不加都无所谓。
这也就是前后指针法的一个**缺陷:如果数组中数据都相等**,效率就会很低。
快排的非递归版本
所以现在已经知道了三种版本的快排,其实也就是三种找基准值的方法。
既然我们的快排使用的是递归,就难免有空间上的缺陷。其实快排还有非递归版本。但是要借助数据结构:栈。
那么现在问题是左右区间再分左右区间时我们怎么找区间呢?因为找基准值时没有使用递归而是在找区间时使用的递归(所以找基准值使用前面说的三种方法的任意一种都行)。

(先将5和0入栈,然后出栈,left=0,right=5,找到基准值为3)
我们知道keyi(基准值)也就能区分左区间和右区间,这两个区间任意哪一个入栈都行。
现在,我们还是一样要现将right入栈再将left入栈(先入右区间),然后再入另一个区间。

此时栈不为空,我们出栈,先出的两个就是左区间,然后去找它的基准值。
然后这样找下去直到right小于left或等于left时,也就是没有数据或者只有一个数据时,构不成有效区间,就不入栈。
左区间所有基准值找完后,就像二叉树一样,开始走右区间。
开始走右区间时也就是刚好栈里剩的两个数据为右区间时。
所以可以看出,我们取栈顶元素就是在模拟递归。
代码参考
现在我们通过代码来看看怎么使用栈进行快排。
//非递归版快排
//借助数据结构——栈
void QuickSortNonR(int* arr, int left, int right)
{ST st;STInit(&st);StackPush(&st, right);StackPush(&st, left);while (!StackEmpty(&st)){//取两次栈顶int begin = StackTop(&st);StackPop(&st);int end = StackTop(&st);StackPop(&st);//找基准值——用双指针法int prev = begin;int cur = begin + 1;int keyi = begin;while (cur <= end){if (arr[cur] <= arr[keyi] && ++prev!=cur){Swap(&arr[cur], &arr[prev]); }cur++;}Swap(&arr[keyi], &arr[prev]);keyi = prev;//根据基准值划分左右区间//左区间:[begin,keyi-1]//右区间:[keyi+1,end]if (keyi + 1 < end)//控制区间有效{StackPush(&st, end);StackPush(&st, keyi + 1);} if (keyi-1>begin)//控制区间有效{StackPush(&st, keyi - 1);StackPush(&st, begin);}}STDestroy(&st);
}
那么到此本文就结束了,祝学习愉快=_=
相关文章:
快速排序(下)
快速排序(下) 前言 在上一篇文章中我们了解了快速排序算法,但那是Hoare的版本,其实还有别的版本:一种是挖坑法,它们的区别主要在于如何找基准值。霍尔的版本思路难理解但代码好理解,挖坑法则是…...
LazyLLM:长上下文场景下提高LLM推理效率
LazyLLM旨在优化大型语言模型(LLM)在处理长文本语境下的推理效率。传统上,LLM的推理过程分为预填充和解码两个阶段,其中预填充阶段负责计算并存储输入提示的所有token的键值(KV)缓存,这一步骤在…...
PDF文件点击打印无反应?是何原因造成能解决吗?
PDF无法打印怎么处理?在我们工作中,经常会遇见各种各样的文件问题,当我们想要将PDF文件打印出来纸质版使用,却不知什么原因,显示PDF无法打印,这时应该怎么处理呢? 一般情况下,PDF文件…...
初学者友好!从零到一快速上手PyCharm安装的超详细图解+避坑指南教程
一,pycharm的官网下载 下载地址:www.jetbrains.com/pycharm/ 本文将从 Python解释器安装到Pycharm专业版安装和配置汉化等使用都进行了详细介绍,希望能够帮助到大家。 Python解释器&Pycharm安装包&Pycharm破姐插件我都打包好了。 …...
AI大模型需要什么样的数据?
数据将是未来AI大模型竞争的关键要素 人工智能发展的突破得益于高质量数据的发展。例如,大型语言模型的最新进展依赖于更高质量、更丰富的训练数据集:与GPT-2相比,GPT-3对模型架构只进行了微小的修改,但花费精力收集更大的高质量…...
Java每日一练_模拟面试题1(死锁)
一、死锁的条件 死锁通常发生在两个或者更多的线程相互等待对方释放资源,从而导致它们都无法继续执行。死锁的条件通常被描述为四个必要条件,也就是互斥条件、不可剥夺条件、占有并等待条件和循环等待条件。 互斥条件:资源不能被共享&#x…...
第三方库认识- Mysql 数据库 API 认识
文章目录 一、msyql数据库API接口1.初始化mysql_init()——mysql_init2.链接数据库mysql_real_connect——mysql_real_connect3.设置当前客户端的字符集——mysql_set_character_set4.选择操作的数据库——mysql_select_db5.执行sql语句——mysql_query6.保存查询结果到本地——…...
Python兼职接单全攻略:掌握技能,拓宽收入渠道
引言 随着Python在数据处理、Web开发、自动化办公、爬虫技术等多个领域的广泛应用,越来越多的人开始利用Python技能进行兼职接单,以此拓宽收入渠道。本文将详细介绍Python兼职接单的注意事项、所需技能水平、常见单子类型、接单途径及平台,帮…...
一键编译并启动一个 ARM Linux qemu 虚拟机
需要事先自己编译 qemu-system-arm 可执行文件; 1,编译创建ARM 虚拟机 #!/usr/bin/bash sudo lssudo apt-get install gcc-arm-linux-gnueabi#wget https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.gztar zxf linux-kernel-v5.10…...
KubeVirt虚拟机存储及网络卸载加速解决方案
1. 方案背景 1.1. KubeVirt介绍 随着云计算和容器技术的飞速发展,Kubernetes已成为业界公认的容器编排标准,为用户提供了强大、灵活且可扩展的平台来部署和管理各类应用。然而,在企业的实际应用中,仍有许多传统应用或遗留系统难…...
JVM—对象已死?
参考资料:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明 在堆里面存放着 Java 世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”。 1、如何判…...
【前端面试3+1】20 css三栏布局6种实现方式、多行文本溢出怎么实现、token过期了怎么处理、【二叉树的中序遍历】
一、css三栏布局6种实现方式 1.浮动布局(Floats) .container {overflow: auto; /* 清除浮动 */ }.left, .right {width: 20%; /* 左右栏宽度 */float: left; }.middle {width: 60%; /* 中间栏宽度 */margin: 0 20%; /* 左右栏宽度 */ } 2.Flexbox .conta…...
【C++】vector介绍以及模拟实现(超级详细<=>源码并存)
欢迎来到我的Blog,点击关注哦💕 【C】vector介绍以及模拟实现 前言vector介绍 vector常见操作构造函数iteratorcapacitymodify vector模拟实现存储结构默认构造函数构造函数拷贝构造函数赋值运算符重载析构函数 容量(capacity)si…...
【Redis 进阶】主从复制(重点理解流程和原理)
在分布式系统中为了解决单点问题(某个服务器程序只有一个节点(只搞一个物理服务器来部署这个服务器程序)。可用性不高:如果这个机器挂了意味着服务就中断了;性能 / 支持的并发量比较有限)。通常会把数据复制…...
Git常用命
转自:https://blog.csdn.net/ahjxhy2010/article/details/80047553 1.查看某个文件或目录的修改历史 git log filename #查看fileName相关的commit记录 git log -p filenam # 显示每次提交的diff#只看某次提交中的某个文件变化,commit-id 文件名…...
强化学习时序差分算法之Q-learning算法——以悬崖漫步环境为例
0.简介 基于时序差分算法的强化学习算法除了Sarsa算法以外还有一种著名算法为Q-learning算法,为离线策略算法,与在线策略算法Sarsa算法相比,其时序差分更新方式变为 Q(St,At)←Q(St,At)α[Rt1γmaxaQ(St1,a)−Q(St,At)] 对于 Sarsa 来说&am…...
111推流111
推流推流...
刷题——数组中只出现一次的两个数字
数组中只出现一次的两个数字_牛客题霸_牛客网 描述 一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 数据范围:数组长度 2≤n≤10002≤n≤1000,数组中每个数的大小 0<val≤100000…...
《剖析程序员面试“八股文”:助力、阻力还是噱头?》
#“八股文”在实际工作中是助力、阻力还是空谈? 作为现在各类大中小企业面试程序员时的必问内容,“八股文”似乎是很重要的存在。但“八股文”是否能在实际工作中发挥它“敲门砖”应有的作用呢?有IT人士不禁发出疑问:程序员面试考…...
Redis过期key的删除策略
在 Redis 中,设置了过期时间的键在过期时间到达后,并不会立即从内存中删除。如果不是,那过期后到底什么时候被删除呢? 下面对这三种删除策略进行具体分析。 立即删除: 立即删除能够保证内存数据的及时性和空间的有效…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...
Python爬虫实战:研究Restkit库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...
