漫画:什么是快速排序算法?
这篇文章,以对话的方式,详细着讲解了快速排序以及排序排序的一些优化。




一禅:归并排序是一种基于分治思想的排序,处理的时候可以采取递归的方式来处理子问题。我弄个例子吧,好理解点。例如对于这个数组arr[] = { 4,1,3,2,7,5,8,0}。

我们把它切割成两部分。

把左半部分和右半部分分别排序好。

之后再用一个临时数组,把这两个有序的子数组汇总成一个有序的大数组

排好之后在复制原源arr数组

这时,源数组就排序完毕了


一禅:左半部分和右半部分的排序相当于一个原问题的一个子问题的,也是采取同样的方式,把左半部分分成两部分,然后…
直到分割子数组只有一个元素或0个元素时,这时子数组就是有序的了(因为只有一个元素或0个,肯定是有序的啊),就不用再分割了,直接返回就可以了(当然,我在讲解这个归并排序的过程中,是假设你大致了解归并排序的前提下的了)


一禅:把一个n个元素的数组分割成只有一个元素的数组,那么我需要切logn次,每次把两个有序的子数组汇总成一个大的有序数组,所需的时间复杂度为O(n)。所以总的时间复杂度为O(nlogn)
快速排序



小白:那倒不是,快速排序的平均时间复杂度也是O(nlogn),不过他不需要像归并排序那样,还需要一个临时的数组来辅助排序,这可以节省掉一些空间的消耗,而且他不像归并排序那样,把两部分有序子数组汇总到临时数组之后,还得在复制回源数组,这也可以节省掉很多时间。


小白:快速排序也是和归并排序差不多,基于分治的思想以及采取递归的方式来处理子问题。例如对于一个待排序的源数组arr = { 4,1,3,2,7,6,8}。

我们可以随便选一个元素,假如我们选数组的第一个元素吧,我们把这个元素称之为”主元“吧。

然后将大于或等于主元的元素放在右边,把小于或等于主元的元素放在左边。

通过这种规则的调整之后,左边的元素都小于或等于主元,右边的元素都大于或等于主元,很显然,此时主元所处的位置,是一个有序的位置,即主元已经处于排好序的位置了。
主元把数组分成了两半部分。把一个大的数组通过主元分割成两小部分的这个操作,我们也称之为分割操作(partition)。
接下来,我们通过递归的方式,对左右两部分采取同样的方式,每次选取一个主元 元素,使他处于有序的位置。

那什么时候递归结束呢?当然是递归到子数组只有一个元素或者0个元素了




分割操作:单向调整
一禅:就按照你说的,选一个主元,你刚才选的是第一个元素为主元,这次我选最后一个为主元吧,哈哈。假设数组arr的范围为[left, right],即起始下标为left,末尾下标为right。源数组如下

然后可以用一个下标 i 指向 left,即 i = left ;用一个下标 j 也指向l eft,即j = left

接下来 j 从左向右遍历,遍历的范围为 [left, right-1] ,遍历的过程中,如果遇到比主元小的元素,则把该元素与 i 指向的元素交换,并且 i = i +1

当j指向1时,1比4小,此时把i和j指向的元素交换,之后 i++。

就这样让j一直向右遍历,直到 j = right

遍历完成之后,把 i 指向的元素与主元进行交换,交换之后,i 左边的元素一定小于主元,而 i 右边的元素一定大于或等于主元。这样,就 i 完成了一次分割了。



一禅一言不合就把代码撸好了,第一版代码如下:
//分割操作:方法一,单向调整
int partion(int a[], int left, int right)
{int temp,pivot;//pivot存放主元int i,j;i = left;pivot = a[right];for(j = left;j < right;j++){if(a[j] < pivot){ //交换值temp = a[i];a[i] = a[j];a[j] = temp;i++;}}a[right] = a[i];a[i] = pivot;return i;//把主元的下标返回
}
//快速排序
void QuickSort(int a[], int left, int right)
{int center;int i,j;int temp;if(left < right){center = partion(a,left,right);QuickSort(a,left,center-1);//左半部分QuickSort(a,center+1,right);//右半部分}
}
分割操作:双向调整



小白:对啊,因为你这调整方法,可能会出现对同一个元素,进行多次交换,例如刚才你在演示的那组元素,在j向右遍历交换的过程中:
第一次:8和1交换
第二次:8和3交换
第三次:8和2交换
8被重复交换了很多次


小白:其实,我们可以这样来调整元素。我还是用我的第一个元素充当主元吧。哈哈
源数组如下

然后用令变量i = left + 1,j = right。然后让 i 和 j 从数组的两边向中间扫描。

i 向右遍历的过程中,如果遇到大于或等于主元的元素时,则停止移动,j向左遍历的过程中,如果遇到小于或等于主元的元素则停止移动。

当i和j都停止移动时,如果这时i < j,则交换 i, j 所指向的元素。此时 i < j,交换8和3

然后继续向中间遍历,直到i >= j。

此时i >= j,分割结束。
最后在把主元与 j 指向的元素交换(当然,与i指向的交换也行)。

这个时候,j 左边的元素一定小于或等于主元,而右边则大于或等于主元。
到此,分割调整完毕
代码如下:
方法二:双向扫描
int partition2( int[] arr, int left, int right)
{int pivot = arr[left];int i = left + 1;int j = right;while(true){ //向右遍历扫描while(i <= j && arr[i] <= pivot) i++;//向左遍历扫描while(i <= j && arr[j] => pivot) j--;if(i >= j)break;//交换int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}//把arr[j]和主元交换arr[left] = arr[j];arr[j] = povit;return j;
}
时间复杂度



小白:因为快速排序的最坏时间复杂度是O(n2)。
例如有可能会出现一种极端的情况,每次分割的时候,主元左边的元素个数都为0,而右边都为n-1个。这个时候,就需要分割n次了。而每次分割整理的时间复杂度为O(n),所以最坏的时间复杂度为O(n2)。
而最好的情况就是每次分割都能够从数组的中间分割了,这样分割logn次就行了,此时的时间复杂度为O(nlogn)。
而平均时间复杂度,则是假设每次主元等概率着落在数组的任意位置,最后算出来的时间复杂度为O(nlogn),至于具体的计算过程,我就不展开了。
不过显然,像那种极端的情况是极少发生的。


小白:哈哈,之所以说它快,是因为它不像归并排序那样,需要额外的辅助空间,而且在分割调整的时候,不像归并排序那样,元素还要在辅助数组与源数组之间来回复制。
稳定性


一禅:不是啊,例如,在排序的过程中,主元在和j交换的时候是有可能破坏稳定性的,例如

把主元与j指向的元素进行交换



//随机选取主元
int random_partition(int[] arr, int left, int right)
{i = random(left, right);//随机选取一个位置//在把这个位置的元素与ar[left]交换swap(arr[i], arr[left]);return partition(arr, left, right);
}
终于写完,这个快排写了挺长时间,觉得有收获的话,可以转发支持一波哦(´-ω-`)。
更多排序算法文章
1. 漫画:什么是冒泡排序算法?
2. 漫画:什么是选择排序算法?
3. 漫画:什么是插入排序算法?
4. 漫画:什么是希尔排序算法?
5. 漫画:什么是归并排序算法?
6. 漫画:什么是快速排序算法?
7. 漫画:什么是堆排序算法?
8. 漫画:什么是基数排序算法?
9. 漫画:什么是外部排序?
10. 什么是计数排序?
11. 十大排序算法极简汇总篇
推荐阅读
下载破 2w+,在校生必看,《程序员内功修炼》第二版出炉
从双非到大厂,帅地写了一本原创PDF送给大家
一个帮你拿offer的校招网站
算法刷题路线(系统+全面)
作者简介:我是帅地,校招拿到过不少大厂offer,毕业去了腾讯研发岗,毕业半年整到人生第一个 100 万,目前专注于写大学规划 + 校招求职相关的内容,著有个人原创网站 PlayOffer。
相关文章:
漫画:什么是快速排序算法?
这篇文章,以对话的方式,详细着讲解了快速排序以及排序排序的一些优化。 一禅:归并排序是一种基于分治思想的排序,处理的时候可以采取递归的方式来处理子问题。我弄个例子吧,好理解点。例如对于这个数组arr[] { 4&…...
vue 3.0组件(下)
文章目录前言:一,透传属性和事件1. 如何“透传属性和事件”2.如何禁止“透传属性和事件”3.多根元素的“透传属性和事件”4. 访问“透传属性和事件”二,插槽1. 什么是插槽2. 具名插槽3. 作用域插槽三,单文件组件CSS功能1. 组件作用…...
双指针 -876. 链表的中间结点-leetcode
开始一个专栏,写自己的博客 双指针,也算是作为自己的笔记吧! 双指针从广义上来说,是指用两个变量在线性结构上遍历而解决的问题。狭义上说, 对于数组,指两个变量在数组上相向移动解决的问题;对…...
Linux之运行级别
文章目录一、指定运行级别基本介绍CentOS7后运行级别说明一、指定运行级别 基本介绍 运行级别说明: 0:关机 1:单用户【找回丢失密码】 2:多用户状态没有网络服务 3:多用户状态有网络服务 4:系统未使用保留给用户 5:图形界面 6:系统重启 常用运行级别是3和5,也可以…...
python搭建web服务器
前言:相信看到这篇文章的小伙伴都或多或少有一些编程基础,懂得一些linux的基本命令了吧,本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python:一种编程语言&…...
【SpringCloud】SpringCloud Feign详解
目录前言SpringCloud Feign远程服务调用一.远程调用逻辑图二.两个服务的yml配置和访问路径三.使用RestTemplate远程调用四.构建Feign五.自定义Feign配置六.Feign配置日志七.Feign调优八.抽离Feign前言 微服务分解成多个不同的服务,那么多个服务之间怎么调用呢&…...
更改Hive元数据发生的生产事故
今天同事想在hive里用中文做为分区字段。如果用中文做分区字段的话,就需要更改Hive元 数据库。结果发生了生产事故。导致无法删除表和删除分区。记一下。 修改hive元数据库的编码方式为utf后可以支持中文,执行以下语句: alter table PARTITI…...
《Netty》从零开始学netty源码(八)之NioEventLoop.selector
目录java原生的WEPollSelectorImplnetty的SelectionKey容器SelectedSelectionKeySetnetty的SelectedSelectionKeySetSelectorSelectorTupleopenSelector每一个NioEventLoop配一个选择器Selector,在创建NioEventLoop的构造函数中会调用其自身方法openSelector获取sel…...
TCP UDP详解
文章目录TCP UDP协议1. 概述2. 端口号 复用 分用3. TCP3.1 TCP首部格式3.2 建立连接-三次握手3.3 释放连接-四次挥手3.4 TCP流量控制3.5 TCP拥塞控制3.6 TCP可靠传输的实现3.7 TCP超时重传4. UDP5.TCP与UDP的区别TCP UDP协议 1. 概述 TCP、UDP协议是TCP/IP体系结构传输层中的…...
超详细淘宝小程序的接入开发步骤
本文是向大家介绍的关于工作中遇到的如何对接淘宝小程序开发的步骤,它能够帮助大家省略在和淘宝侧对接沟通过程中的一些繁琐问题,便捷大家直接快速开展工作~~一、步骤演示1、首先我们打开淘宝开放平台,进入控制台2、进入控制台后,…...
【Python】正则表达式re库
文章目录函数re.match函数re.search函数re.findall函数re.compile函数re.sub函数re.split函数修饰符正则表达式模式正则表达式实例函数 re.match函数 re.match()函数用于尝试从字符串的 起始位置 匹配一个模式,匹配成功返回一个匹配对象,否则返回None。…...
JDK8使用Visual VM根据Dump文件排查OutOfMemoryError生产问题思路
文章目录1. 前言2. 堆内存溢出3. GC执行异常4. 元空间内存溢出5. 创建线程异常6. 内存交换问题7. 数组长度过大8. 系统误杀异常1. 前言 当系统异常产生了dump文件需要我们对其进行排查时,其本质上考验的是我们对于Java运行时内存结构的知识掌握是否牢固以及对业务代…...
2023年网络安全比赛--网络安全事件响应中职组(超详细)
一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 1.找出黑客植入到系统中的二进制木马程序,并将木马程序的名称作为Flag值(若存在多个提交时使用英文逗号隔开,例如bin,sbin,…)提交; 2.找出被黑客修改的系统默认指令,并将被修改的指令里最后一个单词作为Flag值提交; 3.找出…...
【半监督学习】3、PseCo | FPN 错位对齐的高效半监督目标检测器
文章目录一、背景二、方法2.1 基础框架结构2.2 带噪声的伪边界框学习2.3 多视图尺度不变性学习三、实验论文:PseCo: Pseudo Labeling and Consistency Training for Semi-Supervised Object Detection 代码:https://github.com/ligang-cs/PseCo 出处&a…...
Tomcat+Servlet初识
文章目录Tomcat什么是TomcatTomcat的安装启动tomcat静态页面的访问动态页面的访问一个Servlet程序的部署流程Tomcat 什么是Tomcat Tomcat是一个HTTP服务器,在开发或调试Servlet代码时应用广泛;使用Tomcat,实际就是将用户浏览器输入的http请…...
ChatGPT-4 终于来了(文末附免费体验地址)
大家好,我是小钱学长。 ChatGPT4.0 重磅来袭,今天一打开plus页面出现的就是这个GPT-4的体验界面!现在就带大家一起看看GPT4.0。 进入之后是这样的 看到最下面有一行话,目前应该是4个小时限制100条消息。 GPT-4有什么优势&…...
【C++学习】类和对象(中)一招带你彻底了解六大默认成员函数
前言:在之前,我们对类和对象的上篇进行了讲解,今天我们我将给大家带来的是类和对象中篇的学习,继续深入探讨【C】中类和对象的相关知识!!! 目录 1. 类的6个默认成员函数 2. 构造函数 2.1概念介…...
面试——Java基础
说一说你对Java访问权限的了解 在修饰成员变量/成员方法时,该成员的四种访问权限的含义如下: private:该成员可以被该类内部成员访问; default:该成员可以被该类内部成员访问,也可以被同一包下其他的类访…...
JavaWeb——Request(请求)和Response(响应)介绍
在写servlet时需要实现5个方法,在一个service方法里面有两个参数request和response。 浏览器向服务器发送请求会发送HTTP的请求数据——字符串,这些字符串会被Tomcat所解析,然后这些请求数据会被放到一个对象(request)里面保存。 相应的Tom…...
JMeter压测文件上传接口和中文乱码
一、压测文件上传接口 新建测试计划,然后添加需要的元件。 1、添加HTTP信息头管理器 可以在测试计划中添加,也可以在线程组里面添加。 我的接口使用到 token信息。这里在测试计划中添加。 2、添加线程组 上图解释:会在 2秒钟之内启动起来 5…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
