快速排序 - 原理、时空分析、优化

过程

快速排序分为三个过程:

  1. 将数列根据划分值m mm划分为两部分;
  2. 递归到两个子序列中分别进行快速排序;
  3. 不用合并,因为此时数列已经完全有序。

具体来说,第一步要是要把数列分成两个部分,然后保证前一个子数列中的数都小于后一个子数列中的数。对于最优情况,每一次选择的分界值都是序列的中位数。

快速排序归并排序虽然都是划分区间,但是归并排序直接就可以选取中间位置,但快速排序需要选择的是中间数值,中间位置你是可以直接确定的,而中间数值你是无法确定的。为了保证平均时间复杂度,一般是随机选择一个数m mm来当做两个子数列的分界。

其实,快速排序没有指定应如何具体实现第一步,不论是选择m mm的过程还是划分的过程,都有不止一种实现方法。

第三步中的序列已经分别有序且第一个序列中的数都小于第二个数,所以直接拼接起来就好了。

在实现时,只需维护小于等于m mm的边界l o w lowlow,大于m mm的部分自然就唯一确定了。

朴素快速排序

publicstaticvoidquickSort(intl,intr){if(l>=r)// 只有一个数,或范围不存在return;intx=arr[l];// 固定方式选取划分值intmid=partition(l,r,x);// mid 位置已经固定// 处理剩余区间quickSort(l,mid-1);quickSort(mid+1,r);}// 划分数组 ≤x 放左边,>x 放右边publicstaticintpartition(intl,intr,intx){intlow=l,xi=0;for(inti=l;i<=r;i++){if(arr[i]<=x){swap(low,i);if(arr[low]==x)xi=low;low++;}}swap(xi,low-1);// 确保 ≤x 区域的最后一个数字是 xreturnlow-1;}

这里再贴一个 c 风格的,双指针扫描写法的 partition,常见于数据结构教材中。

intpartition(intlow,inthigh,intx){while(low<high){while(low<high&&arr[high]>=x)high--;swap(low,high);while(low<high&&arr[low]<=x)low++;swap(low,high);}returnlow;}

时间复杂度

快速排序的最优时间复杂度和平均时间复杂度为O ( n log ⁡ n ) O(n\log n)O(nlogn),最坏时间复杂度为O ( n 2 ) O(n^2)O(n2)

对于最优情况,每一次选择的分界值都是序列的中位数,此时算法时间复杂度满足的递推式为T ( n ) = 2 T ( n 2 ) + Θ ( n ) T(n) = 2T\left( \frac{n}{2} \right)+Θ(n)T(n)=2T(2n)+Θ(n),由主定理,T ( n ) = Θ ( n log ⁡ n ) T(n)=Θ(n\log n)T(n)=Θ(nlogn)

对于最坏情况,每一次选择的分界值都是序列的最值,此时算法时间复杂度满足的递推式为T ( n ) = T ( n − 1 ) + Θ ( n ) T(n)=T(n-1)+Θ(n)T(n)=T(n1)+Θ(n),易得T ( n ) = Θ ( n 2 ) T(n)=Θ(n^2)T(n)=Θ(n2)

对于平均情况,每一次选择的分界值可以看作是等概率随机的,设划分值在k kk位置,那么:T ( n ) = 1 n ∑ k = 1 n ( T ( k − 1 ) + T ( n − k ) ) + n = 2 n ∑ k = 1 n T ( k ) + n T(n)=\frac{1}{n}\sum_{k=1}^n(T(k-1)+T(n-k))+n=\frac{2}{n}\sum_{k=1}^nT(k)+nT(n)=n1k=1n(T(k1)+T(nk))+n=n2k=1nT(k)+n
由数学归纳法可证明,其数量级为O ( n log ⁡ n ) O(n\log n)O(nlogn)

在实际中,几乎不可能达到最坏情况,而快速排序的内存访问遵循局部性原理(递归处理相邻子数组、原地分区,连续访问缓存行),所以多数情况下快速排序的表现大幅优于堆排序等其他复杂度为O ( n log ⁡ n ) O(n\log n)O(nlogn)的排序算法。

就空间复杂度而言,主要是递归造成的栈空间的使用,最好情况,递归树的深度为log ⁡ 2 n \log_{2}nlog2n,其空间复杂度也就为O ( log ⁡ n ) O(\log n)O(logn),最坏情况,需要进行n − 1 n-1n1递归调用,其空间复杂度为O ( n ) O(n)O(n),平均情况,空间复杂度也为O ( log ⁡ n ) O(\log n)O(logn)

优化

  • 当序列较短时,直接使用插入排序的效率更高;
  • 尾递归(迭代)可以缩减堆栈深度,提高整体性能。

我们还有两条主路径去优化:划分值m mm的选取划分的过程

划分值m mm

如果你用朴素方法中的固定方式选取划分值m mm,比如总选数列第一个或最后一个元素,毒瘤数据能够把朴素的快速排序卡成O ( n 2 ) O(n^2)O(n2),比如升序或降序数列。

  • 通过三数取中,即选取第一个、最后一个以及中间的元素中的中位数。

    • 对于非常大的待排序的数列,也有九数取中,不再详述。
  • 通过随机选取,即随机选一个[ l , r ] [l,r][l,r]上的下标对应的值。虽然随机的常数时间比较大,但只有这一下随机,才能在概率上把快速排序的时间复杂度收敛到O ( n log ⁡ n ) O(n\log n)O(nlogn)

划分过程

朴素方法中,每次划分的过程都只能确定一个位置的值,即p a r t i t i o n partitionpartition返回的位置。

三路快速排序

是快速排序和基数排序的混合。思想基于 荷兰国旗问题。

每次划分过程,将待排数列划分为三个部分:小于m mm、等于m mm以及大于m mm。在处理含有多个重复值的数组时,效率远高于朴素快速排序。其最佳时间复杂度为O ( n ) O(n)O(n)

在实现时,只需维护小于m mm的边界,和大于m mm的边界,等于的部分自然就唯一确定了。

荷兰国旗优化版随机快速排序

publicstaticintfirst,last;publicstaticvoidquickSort(intl,intr){if(l>=r)return;// [l, r+1) -> l + [0, r-l+1)intx=arr[l+(int)(Math.random()*(r-l+1))];partition(l,r,x);intleft=first;intright=last;// 记录一下 lastquickSort(l,left-1);// 经过左半边快排,last 可能被更改quickSort(right+1,r);}publicstaticvoidpartition(intl,intr,intx){first=l;last=r;inti=l;while(l<=last){if(arr[i]==x)i++;elseif(arr[i]<x)swap(first++,i++);elseswap(last--,i);}}
内省排序

是快速排序和堆排序的结合。保证了最差时间复杂度为O ( n log ⁡ n ) O(n\log n)O(nlogn)

内省排序将快速排序的最大递归深度限制为⌊ log ⁡ n ⌋ \lfloor \log n \rfloorlogn,超过限制时就转换为堆排序。这样既保留了快速排序内存访问的局部性,又可以防止快速排序在某些情况下性能退化为O ( n 2 ) O(n^2)O(n2)

SGI C++ STL 的stl_algo.hsort()函数的实现采用了内省排序算法。

习题

洛谷 P1177【模板】快速排序 模板
力扣 912. 排序数组 模板

#atom

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

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

相关文章

Java SpringBoot+Vue3+MyBatis 教师工作量管理系统系统源码|前后端分离+MySQL数据库

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价&#xff0c;所以能给到超低价格。摘要 随着教育信息化的快速发…

企业级企业客户管理系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价&#xff0c;所以能给到超低价格。摘要 随着信息技术的快速发展…

2. 假新闻检测 - 《FakingRecipe: Detecting Fake News on Short Video Platforms from the Perspective of ...》

前言 本文阅读论文《FakingRecipe: Detecting Fake News on Short Video Platforms from the Perspective of Creative Process》。现有的假新闻检测方法主要侧重于分析所呈现内容&#xff0c;而文章的实证分析揭示了假新闻视频在素材选择和编辑方面的独特特征。 核心内容细节…

Java SpringBoot+Vue3+MyBatis 网上超市设计与实现系统源码|前后端分离+MySQL数据库

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价&#xff0c;所以能给到超低价格。摘要 随着互联网技术的快速发…

1. 假新闻检测 - 《Modality Perception Learning-Based Determinative Factor Discovery ...》

前言 本文阅读论文《Modality Perception Learning-Based Determinative Factor Discovery for MultimodalFake News Detection》。虚假新闻通常依赖夸张的语言风格、篡改的图像、不一致的多模态上下文等特征。虚假新闻检测应遵循“逻辑与”原则&#xff0c;即便大部分内容合理…

Java Web 网上购物商城系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价&#xff0c;所以能给到超低价格。摘要 随着互联网技术的快速发…

vscode下载/常用插件分享及如何链接Ubuntu

这里做一个大佬们分享的整合&#xff1a; Vscode下载及常用插件分享&#xff1a; VSCode安装配置使用教程&#xff08;最新版超详细保姆级含插件&#xff09;一文就够了_vscode使用教程-CSDN博客 用Vscode连接Ubuntu&#xff1a; Vscode连接Ubuntu&#xff01;看这一篇就够…

idea不能使用低版本插件问题解决

idea升级之后,插件无法在高版本使用,开发者也不维护了下载插件 https://plugins.jetbrains.com/search?excludeTagsinternal&productsidea修改插件版本范围 将下载的zip压缩包解压,找到插件源代码的jar包里面的jar包和zip包的版本号是一样的,在bin中,根据版本号比较好找编…

MCU+AT到OpenCPU:嵌入式通信技术迭代的必然性(完结篇)

上一篇在充分理解了OpenCPU的技术优势与架构潜力后&#xff0c;一个现实而关键的问题摆在工程师及企业面前&#xff1a;如何在实际工程中&#xff0c;将现有的MCUAT模组架构&#xff0c;安全、平滑地演进至OpenCPU平台&#xff1f;第六章&#xff1a;迁移与融合策略——从MCUAT…

基于Python+Django+SSM美妆产品网络评价数据采集与分析(源码+LW+调试文档+讲解等)/美妆产品评价分析/网络评价数据采集/美妆数据采集/美妆评价分析/美妆产品网络数据/美妆产品评价数据

博主介绍 &#x1f497;博主介绍&#xff1a;✌全栈领域优质创作者&#xff0c;专注于Java、小程序、Python技术领域和计算机毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅&#x1f447;&#x1f3fb; 2025-2026年最新1000个热门Java毕业设计选题…

MCU+AT架构的演进:向OpenCPU转型的必然性(完结篇)

上一篇在充分理解了OpenCPU的技术优势与架构潜力后&#xff0c;一个现实而关键的问题摆在工程师及企业面前&#xff1a;如何在实际工程中&#xff0c;将现有的MCUAT模组架构&#xff0c;安全、平滑地演进至OpenCPU平台&#xff1f;第六章&#xff1a;迁移与融合策略——从MCUAT…

深度实战:AirCloud与excloud扩展库集成下的核心功能应用解析!

随着边缘侧业务复杂度的提升&#xff0c;单一平台能力已难以满足多样化场景需求。AirCloud平台在设备管理、状态同步与远程控制方面表现优异&#xff0c;而excloud扩展库则通过模块化设计补足了功能延展的短板。二者集成后&#xff0c;形成了“基础扩展”的技术合力。聚焦于Air…

快速上手iPerf:新手网络测试环境搭建详解!

快速上手iPerf的关键&#xff0c;在于高效搭建网络测试环境。这款工具的环境搭建流程简洁明了&#xff1a;先在服务端运行监听命令&#xff0c;再在客户端指定目标地址发起测试&#xff0c;即可获取网络带宽、延迟等数据。本文针对新手需求&#xff0c;详细拆解iPerf环境搭建的…

大规模语言模型在精准医疗方案生成中的应用

大规模语言模型在精准医疗方案生成中的应用 关键词:大规模语言模型、精准医疗方案、医疗数据处理、模型应用、医学知识推理 摘要:本文聚焦于大规模语言模型在精准医疗方案生成中的应用。首先介绍了研究的背景、目的、预期读者、文档结构及相关术语。详细阐述了大规模语言模型…

【更新至2024年】1996-2024年各省公路里程数据

【更新至2024年】1996-2024年各省公路里程数据 1、时间&#xff1a;1996-2024年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;公路里程&#xff08;万公里&#xff09; 4、范围&#xff1a;31省 5、指标解释&#xff1a;公路里程指报告期末公路的实际长度…

【更新至2024年】1996-2024年各省铁路营业里程数据

【更新至2024年】1996-2024年各省铁路营业里程数据 1、时间&#xff1a;1996-2024年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;铁路营业里程 4、范围&#xff1a;31省 5、指标解释&#xff1a;铁路营业里程又称营业长度&#xff0c;指投入客货运输正式…

【项目中的经验总结】

知识点一&#xff1a;多电源域下 Dummy Gate 的连接问题 1. 背景说明 在 MOS 管版图中&#xff0c;dummy gate 常用于满足工艺对栅极密度、对称性和边缘效应的要求。 Dummy gate 虽不参与功能&#xff0c;但仍具有栅氧层及栅-源 / 栅-漏寄生电容&#xff0c;不能视为“完全无效…

Node.js用readableLength轻松控流

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Node.js流控新境界&#xff1a;利用readableLength实现高效背压管理目录Node.js流控新境界&#xff1a;利用readableLength实现高…

从C到汇编:参数传递的内存地址探秘

在编程的世界里,了解程序如何在内存中布局和操作是每个程序员的基本功。今天我们来深入探讨一个关于参数传递的经典问题:在C语言中,如何找到一个函数参数在内存中的确切地址。 背景介绍 假设我们有一个C语言函数caller,它调用另一个函数swap_add,并传递两个参数arg1和ar…

[特殊字符]_Web框架性能终极对决:谁才是真正的速度王者[20260107173025]

作为一名拥有10年开发经验的全栈工程师&#xff0c;我经历过无数Web框架的兴衰更替。从早期的jQuery时代到现在的Rust高性能框架&#xff0c;我见证了Web开发技术的飞速发展。今天我要分享一个让我震惊的性能对比测试&#xff0c;这个测试结果彻底改变了我对Web框架性能的认知。…