数据结构(邓俊辉)学习笔记】排序 2——快速排序:性能分析
文章目录
- 1. 不稳定 + 就地
- 2. 最好情况 + 最坏情况
- 3.平均情况
1. 不稳定 + 就地
以下针对刚才所给出的快速排序算法的第一个版本,就其性能做一分析。
首先很遗憾地发现,这个算法是不稳定的。快速排序算法的不稳定性通过我们刚才所举的那个实例可以清楚地看出来。

注意到,在原始的输入序列中有两个5,按照先后次序,我们分别用5A 和5B 来表示。
在经过一次划分之后,我们可以看到这两个元素的位置已经彼此颠倒。实际上这种现象必然是普遍存在的。因为对于任何两个小于候选轴点的元素而言,它们加入子序列 L 的次序必然是颠倒的。同理对于大于候选轴点的雷同元素而言,也有对称的性质。
其次整个算法也是可以就地实现的,也就是说它只需要常数的附加空间。这一点从刚才这组原理和过程图中也可以清晰地看出。

实际上除了原始的输入序列,我们这里只需要维护常数个指针以及用于保存候选轴点的一个单元。
2. 最好情况 + 最坏情况

那么整个算法的运行时间呢?我们知道,对于归并排序而言,整个算法的运行时间可以保证不超过 n*log n。我们也知道其关键在于归并排序可以保证任何一对被划分出来的子任务在规模上都是彼此相当的,也就是规模都接近二分之N。因此总体的运行时间也就是求解两个这样的问题,再加上为了将它们的结果合并所需要的线性时间。
很遗憾,快速排序算法却不能像归并排序算法那样保证子任务划分时的均衡性。实际上partition 算法的每次划分结果与其说是取决于这个算法,不如说取决于最初选定的候选轴点。
如果候选轴点在最终有序列中所对应的秩为 r,那么经划分之后所得到的序列 L 的长度也必然就是 r。而对应的子序列 G 的长度也必然为 n 减 1 再减 r。划分的结果是否均衡完全取决于我们的运气。
-
在最好的情况下,我们的每次划分都是均衡的,或者至少是接近均衡的,于是我们自然可以达到最优的 n*logn。
-
然而反过来,在最坏的情况下,有可能我们的每一次划分都不均衡,甚至极不均衡。比如最为极端的一种情况就是,每一个候选节点都是在当前而言最小或者最大的极值元素,以至于在划分之后,子序列 L 为空或者 G 为空。也就是说,在我们所划分出来的一对子任务中,总是有一个规模为零,而另一个相对于此前的规模只减少了一个单位。
根据这个递推式不难解出,此时算法所需要的总体运行时间必然是平方量级的。也就说与起泡排序等低级算法居然性能是相当的。
当然采用一些简明的策略,在付出足够小的代价之后,我们的确可以在一定程度上降低最坏情况出现的概率。比如我们可以采用所谓随机选取法,也就说不再是每次都固定地将首元素作为候选轴点。而是在整个序列中,随机地选择其一。另一种更为有效的方法是所谓的三者取中法,也就是说我们每次都是在整个序列中随机地抽取3个元素,然后将其中数值居中的那个作为候选轴点。
当然,无论采用什么方法,我们也只能是在一定程度上降低最坏情况出现的概率,而无法根本的杜绝最坏情况的出现。既然如此,我们接下来不得不回答的一个问题就是,就基本的快速排序算法而言,其平均性能又有多高呢?
3.平均情况
非常幸运的是,以上基本的快速排序算法在常规的随机意义下,平均性能的确可以达到最优的 n log n。

以下我们不妨针对最为常见的均匀独立分布来做一精确的估算,也就说我们在这里假设,所有的元素都是均匀的取自于某一个数值范围。同时各元素在确定各自取值时是互不依赖的。
我们来考察任何一个这样的随机序列,调用 partition 算法对它进行的划分将有几种可能呢?无非 n 种可能,具体的哪种情况完全取决于最初所选定的那个候选轴点。
更准确地讲,是这个候选轴点在最终有序列中所具有的秩。如果将候选轴点的这个秩记作 k,那么 partition 算法所输出的子序列 L 长度也应该是 k,这个子序列所对应的那个子任务所需的平均运行时间也因此就可以表示为Tk。对称的 partition 算法所输出的子序列 G 长度应该为 n 减 k 减1,这个子序列所对应的那个子任务从递归的角度来看,所需要的平均运行时间也因此可以表示为 T n 减 k 再减1。这样的一对排序子任务总共所需要的运行时间也自然就是二者之和。
进一步的,既然按照假设这里服从均匀独立分布,因此各种情况出现的概率应该均等。具体来说都是 n 分之1。因此所有这些情况所对应的平均运行时间,也就是用这个概率对它们的总和进行平均。以下的分析,焦点就会聚在这个求和号上。尽管这个求和涉及到前后两个序列,但是略加观察之后,我们不难发现,这两个序列的求和应该完全是相等的,你能看出原因来吗?
没错,这两个序列的取值范围都是从 0 到 n 减1 ,只不过前者是递增的,从0到 n 减1,而后者只不过是递减的,从 n 减1到0。因此我们只需保留其中的一项,同时作为补偿将它的系数加倍。
接下来我们将这个等式的两端同时乘以 n,于是就可以得到这样一个等式。如果将其中所有的 n 都替换为 n 减1,我们又可以进而得到下面这个等式。现在我们只需将这两个等式相减,就可以得到这样一个等式。除了系数,这个等式主要都包含一个 Tn 以及两个 T n 减一。
接下来我们只需对 Tn 和 Tn 减1合并同类项,就可以得到这样一个等式。对于这样一个等式,我们不妨令它的左右两端同时除以 n 以及 n 加1。
于是就可以得到这样一个等式,如果我们将这个等式的左侧表示和理解为另一个函数 Sn,那么右侧的这一项也就对应于 Sn 减1。这样我们也得到了一个关于 Sn 的简明递推式。
因此接下来,我们可以进而将右侧的 Sn 减 1 替换为 Sn 减2。当然,为此我们需要追加一项,这种地推可以持续进行下去,也就说我们可以将 Sn 减2替换为 Sn 减3,再将 Sn 减3替换为 Sn 减4以及 Sn 减4替换成 Sn 减5,诸如此类。
在递推到最终一步之前,我们所引入的各项将构成一个级数。你应该看得出来这是一个什么级数。没错,调和级数。我们在第一章就曾介绍过,就渐进意义而言,调和级数是与自然对数 log n 同阶的。
由此可见,我们这里所需要估计的快速排序算法的平均运行时间在渐进意义下的确不超过 n * log n,那么它对应的常系数呢?为此,我们只需将 log n 替换为以2为底的对数,相应的也自然可以得知常系数应为两倍的 ln2,具体来说也就大致为1.39。
这样小的一个长系数,也保证了快速排序算法在通常情况下的优异性能,也就是说,快速排序的确名符其实。
相关文章:
数据结构(邓俊辉)学习笔记】排序 2——快速排序:性能分析
文章目录 1. 不稳定 就地2. 最好情况 最坏情况3.平均情况 1. 不稳定 就地 以下针对刚才所给出的快速排序算法的第一个版本,就其性能做一分析。 首先很遗憾地发现,这个算法是不稳定的。快速排序算法的不稳定性通过我们刚才所举的那个实例可以清楚地看…...
在postman中使用javascript脚本生成sign签名
大多数线上api接口服务都需要提供签名才可以正常访问。虽然带来了安全,单有时为了快速验证接口的某个功能,就不得不编写代码,计算签名然后再请求。那么,使用postman提供的script功能,是否能实现签名计算功能吗…...
设计模式—2—单例模式
文章目录 一、单例模式概述二、单例模式特点三、示例3.1、基本实现(懒汉式-线程不安全)3.2、基本实现(懒汉式-线程安全)3.3、基本实现(饿汉式) 四、总结 一、单例模式概述 单例模式(Singleton …...
服务器数据恢复—磁盘坏扇区导致raid6阵列崩溃的数据恢复案例
服务器存储数据恢复环境: 一台存储中有一组由12块SAS硬盘组建的raid6磁盘阵列,划分了1个卷,由数台Vmware ESXI主机共享存储。卷中存放了大量的Windows系统虚拟机。这些虚拟机系统盘大小一致,数据盘大小不确定,数据盘都…...
原码、反码、补码
目录 背景: 1.原码 举例: 2.反码: 举例 : 3.补码: 举例: 背景: 在计算机科学中,原码、反码和补码是三种用于表示有符号整数(即包含正负数) 的二进制编码方式。它们各自有其独特的定义和用途&#x…...
排序算法之计数排序详细解读(附带Java代码解读)
计数排序(Counting Sort)是一种非比较型的排序算法,它通过统计每个元素的出现频率,然后计算元素的位置信息,最后将元素放到正确的位置,从而实现排序。计数排序特别适用于元素范围有限的情况,比如…...
Linux:如何使用 Crontab
今天想了解一下Linux Crontab。嗯,在Windows上,可以看做和定时任务差不多。 “要在特定时间进行特定工作。” 如果是这样,可以使用crontab,轻松使用Linux。 1. 基本 (crontab basic) 先看一下基本的crontab使用方法吧。在Linu…...
AI模型:追求全能还是专精?-- 之7 智能工厂程序设计
Q1、感觉上上面离我想做的事情却来越远了。我们跳过讨论直接进入程序设计吧。StringProcessor(文字/信息/数字)抽象代理工厂-创造 Universal given时空区域 |bar PROCESS: 页面版块的图式schema/概念的KE图式CaseFilter 一般应用工厂-制造- General sign…...
如何在本地服务器部署SeaFile自托管文件共享服务结合内网穿透打造私有云盘?
文章目录 1. 前言2. SeaFile云盘设置2.1 Owncould的安装环境设置2.2 SeaFile下载安装2.3 SeaFile的配置 3. cpolar内网穿透3.1 下载安装3.2 Cpolar注册3.3 Cpolar云端设置3.4 Cpolar本地设置 4.公网访问测试5.结语 1. 前言 本文主要为大家介绍,如何使用两个简单软件…...
学习记录:js算法(二十五):合并两个有序链表
文章目录 合并两个有序链表我的思路网上思路 总结 合并两个有序链表 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 图一 示例 1:(如图一) 输入:l1 [1,2,4], l2 [1,3,4] …...
43. 1 ~ n 整数中 1 出现的次数【难】
comments: true difficulty: 中等 edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9843.%201%EF%BD%9En%E6%95%B4%E6%95%B0%E4%B8%AD1%E5%87%BA%E7%8E%B0%E7%9A%84%E6%AC%A1%E6%95%B0/README.md 面试题 43. 1 ~ n 整数中 1 …...
K8S - 理解volumeMounts 中的subpath
在上一篇文章中 springboot service如何动态读取外部配置文件 介绍了springboot 中如何实时读取外部配置文件的内容 部署在K8S 接下来我把它部署在k8s 首先, 我们把配置文件放入项目某个目录 这步部是必须的, 毕竟我们要引入是项目外部的文件…...
java工程师成功转型大数据
时间:2024年09月06日 作者:小蒋聊技术 邮箱:wei_wei10163.com 微信:wei_wei10 音频:喜马拉雅 希望大家帮个忙!如果大家有工作机会,希望帮小蒋推荐一下,小蒋希望遇到一个认真做事…...
visual studio 2022更新以后,之前的有些工程编译出错,升级到Visual studio Enterprise 2022 Preview解决
系列文章目录 文章目录 系列文章目录前言一、解决方法 前言 今天遇到一个问题:visual studio 2022升级成预览版以后,之前的有些工程编译出错。首先代码、项目设置都没有改变,只是更新了visual studio 2022。 在编译工程时,编译器…...
Linux 性能调优技巧
1理解 Linux 性能的基本组成 CPU 使用率:衡量 CPU 在单位时间内被占用的程度。内存使用:关注的是活跃内存与缓存内存的比例,以及是否有过多的交换。I/O 性能:磁盘读写速度直接影响应用程序的响应时间和吞吐量。网络性能ÿ…...
【网络安全】WordPress Uncontrolled Resource Consumption
未经许可,不得转载。 文章目录 WordPresswp-cron.php实战漏洞危害解决措施WordPress WordPress 是全球最广泛使用的内容管理系统(CMS),目前约有 43% 的网站依赖于它。由于其用户友好的界面和丰富的插件功能,WordPress 成为了全球最受欢迎的 CMS。 然而,在使用 WordPres…...
gitee绑定公钥后依旧无法使用_gitee push添加公钥无效
解决: 步骤按照官网操作即可:gitee官方说明 看看远程地址是否使用的http模式,是的话换ssh模式...
Linux 删除 当前下的 mysql-8.0.31 空文件夹
在Linux中,如果你想要删除当前目录下的名为mysql-8.0.31的空文件夹(即该文件夹内没有任何文件或子文件夹),你可以使用rmdir命令。但是,如果mysql-8.0.31文件夹并非完全为空(即它包含文件或子文件夹…...
2024,中国服务器操作系统迎云智主升浪
“主升浪”描述了股市中一轮行情中涨幅最大、上升持续时间最长的阶段。2024年,云与AI深度融合形成了数字经济主升浪,从而打开了中国服务器操作系统的黄金机遇期。 2024年注定将成为非常不平凡的一年。不仅是实现“十四五”规划目标任务的关键一年&#x…...
STM32快速复习(九)RTC时钟模块
文章目录 前言一、RTC是什么?RTC的工作原理?二、库函数以及示例1.标准库函数2.示例代码 总结 前言 STM32 的实时时钟(RTC)是一个独立的定时器。 STM32 的 RTC 模块拥有一组连续计数的计数器,在相应软件配置下…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
