news 2026/5/11 1:17:21

快速排序(Quick Sort)的“死穴”

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
快速排序(Quick Sort)的“死穴”

快速排序(Quick Sort)的“死穴”,也就是它的最坏情况

简单来说,它的意思是:如果你运气不好,选的基准值(Pivot)太极端,快速排序就会变得非常慢,慢得像冒泡排序一样。

我来把这张图里的“行话”翻译成大白话,配合具体的例子演示。


1. 快速排序的理想状态 vs. 糟糕状态

快速排序的核心思想是“分治”(分而治之)。

  • 理想情况:选一个基准值(比如中间大小的数),它能把数组一分为二(左边一半,右边一半)。每轮都减半,速度极快。

  • 糟糕情况(PPT里的情况):选的基准值是最大最小的数。它没能把数组切开,只是把最边上的一个切下来了,剩下的一大坨还在那一侧。


2. 结合 PPT 中的例子演示

PPT 里举了两个例子,一个是倒序的,一个是正序的。通常教科书里的快速排序默认取第一个元素作为基准值(Pivot)

例子 A:倒序数组(90, 85, 79, 74, ...)

假设我们总是取第一个数做基准(Pivot = 90)。

  1. 第一轮

    • 基准:90

    • 比较:剩下的所有数 (85, 79, 74...) 都比 90 小。

    • 划分结果

      • 左边子序列:(85, 79, 74, 68, 50, 46)(也就是除了90以外的所有人)

      • 右边子序列:()(空空如也,因为没人比90大)

    • 代价:我们忙活了一整轮,只把90这一个数排好了位置。

  2. 第二轮(处理左边那一堆):

    • 基准:85(现在的第一个)

    • 比较:剩下的 (79, 74...) 都比 85 小。

    • 划分结果:又是一边倒。85 右边是空的,左边还是那一堆。

结论:这就像切西瓜,原本想一刀两半,结果你每一刀都只切下来薄薄的一层皮。你要切 N 次才能切完。

例子 B:正序数组(46, 50, 68, ...)

道理是一样的。

  1. 基准:46。

  2. 比较:剩下的所有数 (50, 68...) 都比 46 大。

  3. 划分结果

    • 左边子序列:()(空的)

    • 右边子序列:(50, 68, 74, ...)(所有人都在右边)


3. 为什么 PPT 说“退化为冒泡排序”?

你看上面的过程:

  • 快速排序(最坏情况):第一轮搞定 1 个数(90),第二轮搞定 1 个数(85),第三轮搞定 1 个数(79)...

  • 冒泡排序:第一轮冒出一个最大值(搞定1个),第二轮冒出第二大值(搞定1个)...

它们的工作效率变成一模一样的了!

  • 正常快排复杂度:O(nlogn) (类似树形结构,层数少)

  • 退化后的复杂度:O(n2) (类似链表结构,层数变成了 N 层,非常慢)

4. 树形图解对比

为了让你直观感受区别,我画个图:

理想的快速排序(平衡树):每次都运气好,选到中间值,两边均匀。

代码段

graph TD A[50] --> B[25] A --> C[75] B --> D[10] B --> E[40] C --> F[60] C --> G[90]

PPT 里的最坏情况(歪脖子树):每次都选到最大或最小(有序数组选第一个数就会这样)。

代码段

graph TD A[90] --> B[85] B --> C[79] C --> D[74] D --> E[68] E --> F[...]

看,下面这棵“歪脖子树”明显比上面的“平衡树”要深得多,走的路更长,所以效率极低。

总结 PPT 的红框结论

“快速排序不适于对原本有序或基本有序的记录序列进行排序。”

这句话的意思是: 如果你拿到一个数组,发现它已经是排好序的(或者倒序的),这时候如果你还傻乎乎地用“取第一个元素当基准”的快速排序去排它,那就是自寻死路,效率最低。

那怎么办?实际工程中,为了避免这种尴尬,我们通常随机选基准,或者三数取中(取头、中、尾三个数的中间值当基准),这样就能避开这种“死穴”了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 12:48:49

25、技术探索:Google App Engine、Zenoss与Python包管理

技术探索:Google App Engine、Zenoss与Python包管理 一、Google App Engine数据查询与路由 在Google App Engine开发中,数据查询与路由是重要的环节。以下是一段用于从数据存储中获取最后10条记录并进行处理的代码: collection = [] #grab last 10 records from datasto…

作者头像 李华
网站建设 2026/5/10 15:07:36

每日一练:流星雨

题目描述贝西听说一场非凡的流星雨即将来临;报告称这些流星将撞击地球并摧毁它们所碰到的任何东西。为了安全,她发誓要找到一个安全的位置(一个从未被流星摧毁的地方)。她目前在坐标平面的原点放牧,想要移动到一个新的…

作者头像 李华
网站建设 2026/5/1 22:11:19

21、SNMP网络管理与数据中心发现实战

SNMP网络管理与数据中心发现实战 1. 配置Net - SNMP 当你要在想要监控的客户端上安装Net - SNMP时,应使用主机资源MIB(Management Information Base,管理信息库)来编译Net - SNMP。具体操作步骤如下: ./configure -with-mib-modules=host运行 configure 时,它会尝试…

作者头像 李华
网站建设 2026/5/7 0:41:02

25、技术探索:数据查询、服务器管理与Python包管理

技术探索:数据查询、服务器管理与Python包管理 数据查询代码分析 在数据处理中,我们常常需要从数据存储中获取特定的记录。以下是一段相关代码: collection = [] #grab last 10 records from datastore query = ChangeModel.all().order(-date) records = query.fetch(l…

作者头像 李华
网站建设 2026/5/6 17:52:57

中国独立开发者创业实战指南:从技术到商业的变现路径

中国独立开发者创业实战指南:从技术到商业的变现路径 【免费下载链接】chinese-independent-developer 分享中国独立开发者们正在进行的工作和项目的列表。 项目地址: https://gitcode.com/GitHub_Trending/ch/chinese-independent-developer 在当今技术创业…

作者头像 李华
网站建设 2026/5/10 16:22:12

从零构建大模型智能体:OpenAI Function Calling智能体实战

引言 随着大语言模型逐步具备“理解—推理—行动”的能力,如何让模型稳定、可控地调用外部工具,已成为构建智能体(Agent)系统的关键一环。相比早期基于文本协议的工具调用方式,OpenAI 推出的 Function Calling&#x…

作者头像 李华