【以无克有】排序之随机快速排序
分治就是:抽刀断水水更流,举杯消愁愁更愁
文章目录
- 快速排序原理(最常见的双端扫描思路)
- 原理讲解
- 代码实现
- 分区(Partition)部分:
- 递归排序部分:
- 复杂度简要分析
- 例题
- 随机快速排序模板
- 快排应用之第k小数(不去重)
- 参考资料及推荐
- 总结
快速排序原理(最常见的双端扫描思路)
原理讲解
-
分治策略:拆解问题的艺术
快速排序的核心是分治法,即“分而治之”。想象你要给全班同学按身高排序,如果直接比较所有人会很麻烦。于是你选出一个“基准同学”,让比他矮的站左边,高的站右边。这样一来,大问题就拆成了两个小问题——只需分别给左右两边的队伍排序即可。 -
关键操作:基准选择与分区:
- 选基准(Pivot)
这个基准相当于划分队伍的“标尺”,选数组第一个或最后一个元素或位于中间的元素(《算法导论》基础版本的做法)。比如选最后一个同学的身高作为基准,但实际应用中通常采用随机选择数组中的某元素的优化策略。 - 分区(Partition)
这是快速排序的精华步骤。你需要通过两指针像“夹击”一样调整数组:左指针从起点向右扫描,寻找比基准大的元素。右指针从终点向左扫描,寻找比基准小的元素。当两指针找到不满足条件的元素时,交换它们的位置,直到两指针相遇。此时,基准的正确位置就确定了——左边全比它小,右边全比它大。
- 选基准(Pivot)
-
递归处理:化整为零
分区完成后,对左右两个子数组重复上述过程,直到每个子数组只剩一个或零个元素(递归终止条件)。就像把大队伍不断分成小队,直到每个小队已经自然有序,无需再分。
代码实现
分区(Partition)部分:
这里笔者提供两个思路,一个是leetcode上的模板,另一个是让deepseek评判出来的较优写法
//力扣版
int partition(int* arr, int l, int r) {// 随机选择枢轴:避免最坏情况时间复杂度int pivot = arr[l + rand() % (r - l + 1)];// 初始化指针i和j为区间外,后续通过do-while先移动再判断int i = l - 1, j = r + 1; //注意并非l与rwhile (i < j) { // 循环直到指针相遇或交叉do i++; while (arr[i] < pivot); // 从左找第一个≥pivot的元素do j--; while (arr[j] > pivot); // 从右找第一个≤pivot的元素if (i < j) swap(arr[i], arr[j]); // 交换并继续循环}return j; // 返回分界点j,后续递归区间为[l, j]和[j+1, r]
}//deepseek版
int partition(int* arr, int l, int r) {// 随机选择枢轴(与力扣版相同)int pivot = arr[l + rand() % (r - l + 1)];// 初始化指针i和j为区间端点(而非区间外)int i = l, j = r;while (i <= j) { // 循环条件允许i和j相等while (arr[i] < pivot) i++; // 从左找第一个≥pivot的元素while (arr[j] > pivot) j--; // 从右找第一个≤pivot的元素if (i <= j) { // 允许i和j相等时交换swap(arr[i], arr[j]);i++; // 交换后移动指针,避免重复比较j--;}}return j; // 返回分界点j,后续递归区间为[l, j]和[j+1, r]
}
递归排序部分:
//用递归树的思路来理解:
//1.根节点对应初始数组,通过partition将数组分为左(≤基准值)、右(≥基准值)两段,基准值定位到最终位置j。
//2.子树生成:递归处理左区间[l,j]和右区间[j+1,r],形成左右子树分支。
//3.叶子节点:当区间长度≤1(l≥r)时终止递归,确保底层无子节点。
void quick_sort(int* arr,int l,int r)
{if(l >= r) return;int j = partition(arr,l,r);quick_sort(arr,l,j);quick_sort(arr,j+1,r);
}
复杂度简要分析
- 快速排序的整体时间复杂度由递归深度和每次分区的成本共同决定:
- 最好情况:
每次分区都能将数组均匀划分为两部分(例如基准元素选择为中位数),此时递归深度为 O(log n) ,每层分区总操作次数为 O(n) 。总时间复杂度为 O(n log n) 。例子:对随机无序数组进行排序,且每次分区基准选择合理即选择到了中位数。 - 最坏情况:
每次分区极度不平衡(例如数组已完全有序且基准固定选择首元素),此时由于选择的不合理每次只减少一个元素,所以每层分区总操作次数增加到了 O(n) ,递归深度退化为 O(n) ,总时间复杂度为 O(n²) 。例子:对已升序排列的数组使用快速排序,且基准始终选择第一个元素。 - 平均情况:
假设分区大致平衡(例如通过随机化或三数取中法优化基准选择),递归深度仍为 O(log n) ,总时间复杂度保持 O(n log n)。
例题
随机快速排序模板
例题:P1177 【模板】排序
#include <bits/stdc++.h>
using namespace std;void quick_sort(int *arr, int l, int r)
{if (l >= r) return;int base = arr[l + rand() % (r-l+1)], i = l, j = r; // 因为java源码的实现中有pivot变量使用很多人喜欢用pivot表示base,pivot支点感觉并不比base基准表述得更形象while (i <= j){while (arr[i] < base) i++;while (arr[j] > base) j--;if (i <= j){swap(arr[i], arr[j]);i++;j--; // 防止两个相同值死循环}}quick_sort(arr, l, j);quick_sort(arr, i, r);
}int main()
{int m;cin >> m;int *xp = (int *)malloc(m * sizeof(int));for (int i = 0; i < m; ++i){cin >> xp[i];}quick_sort(xp, 0, m - 1);for (int i = 0; i < m; ++i){cout << xp[i] << " ";}
}
快排应用之第k小数(不去重)
例题:P1923 【深基9.例4】求第 k 小的数
#include <bits/stdc++.h>
using namespace std;int partition(int* arr,int l,int r)
{int pivot = arr[l + rand()%(r-l+1)],i=l-1,j=r+1;while(i < j){do i++;while(arr[i] < pivot);do j--;while(arr[j] > pivot);if(i < j) swap(arr[i],arr[j]);}return j;
}int quick_select(int* arr,int l,int r,int k)
{if(l >= r) return arr[l];int j = partition(arr,l,r);int left_len = j - l + 1;if(k < left_len) return quick_select(arr,l,j,k);else return quick_select(arr,j+1,r,k-left_len);
} int main()
{ios::sync_with_stdio(false);cin.tie(0);int n,k;cin >> n >> k;int* arr = (int*)malloc(n*sizeof(int));for(int i=0;i<n;++i) cin >> arr[i];cout << quick_select(arr,0,n-1,k) << endl;free(arr);return 0;
}
参考资料及推荐
【YouTube大神Abdul Bari】 终极算法课程合集
两种思维模式秒杀所有递归算法,模板 + 可视化
左程云—算法讲解023【必备】随机快速排序
总结
在这片由比特构筑的星空中,快速排序如同巴赫的赋格曲般精妙——混沌的数组在基准值的选择中逐渐显露出潜藏的秩序。分治哲学如同希腊神话中普罗克鲁斯忒斯的床榻,以递归为刻刀将庞杂数据重塑成可解的形态。那些看似无序的字节序列,实则是尚未完成自我梳理的德罗斯特效应画卷。
程序员如同手持奥卡姆剃刀的炼金术士,在指针的华尔兹中领悟递归的复调之美。每个基准选择都是笛卡尔坐标系里的理性抉择,每次分区操作都像《神曲》中贝雅特丽齐引领但丁穿越九重天般层层递进。当代码突破迷雾时,算法不再是冰冷的指令集,而成为揭示宇宙递归本质的启示录。
快速排序的伟大不在于它征服了O(n²)的混沌,而在于它谦卑地展示了:即便是最混乱的数据尘埃,也遵循着分形几何般的自相似规律。就像博尔赫斯笔下的巴别图书馆,每行代码都是通向有序宇宙的密道,每个递归调用都是对世界本质的普鲁斯特式追索。
相关文章:
【以无克有】排序之随机快速排序
分治就是:抽刀断水水更流,举杯消愁愁更愁 文章目录 快速排序原理(最常见的双端扫描思路)原理讲解代码实现分区(Partition)部分:递归排序部分: 复杂度简要分析例题随机快速排序模板快排应用之第k小数(不去重) 参考资料及推荐总结 快…...
React源码解读
配置React源码本地调试环境 本次环境构建采用了node版本为16、react-scripts 版本号为 3.4.4,源码下载地址 react源码调试: react源码调试环境 使用 create-react-app 脚手架创建项目 npx create-react-app react-test 进入刚刚下载的目录,弹射 crea…...
[极客大挑战 2019]Havefun1
[极客大挑战 2019]Havefun1 代码审计发现 根据代码逻辑,要求传入’cat’参数,值为’dog’时执行if的操作,所以构造参数: ?catdog获得flag...
Ai人工智能的未来:趋势、挑战与机遇
Ai人工智能的未来:趋势、挑战与机遇 引言 人工智能(AI)已经成为当代科技发展的核心驱动力,其影响力渗透到各个行业,并塑造了我们未来的社会结构。无论是在医疗、金融、制造业,还是在自动驾驶、智能客服、…...
MG协议转换器:破解暖通设备通讯壁垒的智能钥匙
在智能化楼宇管理中,暖通空调系统(HVAC)的高效运行直接影响建筑的能耗控制与用户体验。然而,暖通设备品牌众多、协议不统一的问题长期困扰着运维人员:不同厂商的冷水机组、风机盘管、传感器等设备因采用Modbus、BACnet…...
【赵渝强老师】Spark的容错机制:检查点
由于Spark的计算是在内存中完成,因此任务执行的生命周期lineage(血统)越长,执行出错的概念就会越大。Spark通过检查点Checkpoint的方式,将RDD的状态写入磁盘进行持久化的保存从而支持容错。如果在检查点之后有节点出现…...
算法兵法全略(译文)
目录 始计篇 谋攻篇 军形篇 兵势篇 虚实篇 军争篇 九变篇 行军篇 地形篇 九地篇 火攻篇 用间篇 始计篇 算法,在当今时代,犹如国家关键的战略武器,也是处理各类事务的核心枢纽。算法的世界神秘且变化万千,不够贤能聪慧…...
react传递函数与回调函数原理
为什么 React 允许直接传递函数? 回调函数核心逻辑 例子:父组件控制 Modal 的显示与隐藏 // 父组件 (ParentComponent.tsx) import React, { useState } from react; import { Modal, Button } from antd; import ModalContent from ./ModalContent;co…...
多媒体术语扫盲备忘录
DRM DRM: Digital Rights Management, 数字版权保护。 广义上讲,能够保护数字版权(不单单是音视频)都可以叫做DRM。 国外主要分为三大类, Google的Widevine, MicroSoft的 PlayReady, 以及 Apple的 FairPlay. 更多细节请参考此文章. Google Widevine: …...
Node.js 调用 DeepSeek API 完整指南
简介 本文将介绍如何使用 Node.js 调用 DeepSeek API,实现流式对话并保存对话记录。Node.js 版本使用现代异步编程方式实现,支持流式处理和错误处理。 1. 环境准备 1.1 系统要求 Node.js 14.0 或更高版本npm 包管理器 1.2 项目结构 deepseek-proje…...
盛铂科技 SMF106 低相位噪声贴片式频率综合器模块
在现代通信和电子设备领域,频率综合器作为关键组件,其性能优劣直接影响系统的整体表现。盛铂科技的 SMF106 低相位噪声贴片式频率综合器,以其卓越的性能和独特设计,成为众多高性能系统的选择。 一、频率覆盖范围广,步进…...
小米 R3G 路由器(Pandavan)实现网络打印机功能
小米 R3G 路由器(Pandavan)实现网络打印机功能 一、前言 家中有多台 PC 设备需要打印服务,但苦于家中的 Epson L380 打印机没有网络打印功能,并且配置 Windows 共享打印机实在是过于繁琐且需要共享机保持唤醒状态过于费电。想到…...
Okay, But Please Don’t Stop Talking
Okay, But Please Don’t Stop Talking 研发背景 现有问题:像ChatGPT的高级语音模式这类先进的语音对语音系统,容易被“我明白”“嗯哼”等在人类对话中常见的插入语打断。这表明现有语音交互系统在处理自然对话中的语音重叠情况时存在不足。 新的尝试&…...
Python的那些事第二十一篇:Python Web开发的“秘密武器”Flask
基于 Flask 框架的 Python Web 开发研究 摘要 在 Web 开发的江湖里,Python 是一位武林高手,而 Flask 则是它手中那把小巧却锋利的匕首。本文以 Flask 框架为核心,深入探讨了它在 Python Web 开发中的应用。通过幽默风趣的笔触,结合实例和表格,分析了 Flask 的特性、优势以…...
欧拉函数杂记
定义 φ ( n ) \varphi (n) φ(n)表示 [ 1 , n ] [1,n] [1,n]中与 n n n互质的数的个数。 性质 φ ( p ) p − 1 , p ∈ P \varphi (p)p-1,\ p\in \mathbb {P} φ(p)p−1, p∈P φ ( n ) n ∏ i 1 m p i − 1 p i \varphi (n)n\prod_{i1}^{m} \frac{p_i-1}{p_i} φ(n)ni1∏…...
基于IOS实现各种倒计时功能
ZJJTimeCountDown 效果图 特点: 1、已封装,支持自定义 2、支持文本各种对齐模式 3、各种效果都可以通过设置 ZJJTimeCountDownLabel 类属性来实现 4、支持背景图片设置 5、分文本显示时间时,支持设置文字大小,来动态设置每个文本…...
Linux(Centos 7.6)命令详解:head
1.命令作用 将每个文件的前10行打印到标准输出(Print the first 10 lines of each FILE to standard output) 2.命令语法 Usage: head [OPTION]... [FILE]... 3.参数详解 OPTION: -c, --bytes[-]K,打印每个文件的前K字节-n, --lines[-],打印前K行而…...
微软 Microsoft Windows Office Professional LTSC 2024 专业增强版
Office 链接:https://pan.xunlei.com/s/VOIyE3ALg0hDvQfj47cLf3MdA1?pwdvzuz#...
【愚公系列】《Python网络爬虫从入门到精通》009-使用match()进行匹配
标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度…...
Spring Boot 3 集成Xxl-job 3.0.0 单机
下载Xxl-job项目 https://gitee.com/xuxueli0323/xxl-jobhttps://github.com/xuxueli/xxl-job 创建相关数据库 数据库文件再/xxl-job/doc/db/tables_xxl_job.sql直接在数据库中运行SQL文件即可创建相关数据库 配置调度中心 打开项目找到 xxl-job-admin模块找到/xxl-job/xx…...
DeepSeek自动批量写作的AI软件
DeepSeek作为一款专注于数据处理与分析的AI软件,凭借其强大的功能和精准的分析能力,正在帮助企业实现智能化升级。无论是数据分析、市场预测还是内容创作,DeepSeek都能提供高效的解决方案。 无法使用Deepseek批量创作文案的,可在1…...
NLLB 与 ChatGPT 双向优化:探索翻译模型与语言模型在小语种应用的融合策略
作者:来自 vivo 互联网算法团队- Huang Minghui 本文探讨了 NLLB 翻译模型与 ChatGPT 在小语种应用中的双向优化策略。首先介绍了 NLLB-200 的背景、数据、分词器和模型,以及其与 LLM(Large Language Model)的异同和协同关系。接着…...
OpenCV机器学习(4)k-近邻算法(k-Nearest Neighbors, KNN)cv::ml::KNearest类
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::ml::KNearest 是 OpenCV 机器学习模块中的一部分,它提供了实现 k-近邻算法(k-Nearest Neighbors, KNN)的…...
在nodejs中使用RabbitMQ(三)Routing、Topics、Headers
示例一、Routing exchange类型direct,根据消息的routekey将消息直接转发到指定队列。producer.ts 生产者主要发送消息,consumer.ts负责接收消息,同时也都可以创建exchange交换机,创建队列,为队列绑定exchangeÿ…...
浏览器扩展实现网址自动替换
作为一个开发爱好者,不能顺畅访问github是很痛苦的,这种状况不知道何时能彻底解决。 目前也有很多方案可以对应这种囧况,我此前知道有一个网站kkgithub,基本上把github的静态内容都搬了过来,我们如果需要访问某个githu…...
《open3d qt 网格泊松采样成点云》
open3d qt 网格泊松采样成点云 效果展示二、流程三、代码效果展示 效果好一点,速度慢一点。 二、流程 创建动作,链接到槽函数,并把动作放置菜单栏 参照前文 三、代码 1、槽函数实现 void on_actionMeshPossionSample_triggered()//泊松采样 void MainWindow::...
从算法到落地:DeepSeek如何突破AI工具的同质化竞争困局
🎁个人主页:我们的五年 🔍系列专栏:Linux网络编程 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 Linux网络编程笔记: https://blog.cs…...
阿里云一键部署DeepSeek-V3、DeepSeek-R1模型
目录 支持的模型列表 模型部署 模型调用 WebUI使用 在线调试 API调用 关于成本 FAQ 点击部署后服务长时间等待 服务部署成功后,调用API返回404 请求太长导致EAS网关超时 部署完成后,如何在EAS的在线调试页面调试 模型部署之后没有“联网搜索…...
python学opencv|读取图像(六十六)使用cv2.minEnclosingCircle函数实现图像轮廓圆形标注
【1】引言 前序学习过程中,已经掌握了使用cv2.boundingRect()函数实现图像轮廓矩形标注,相关文章链接为:python学opencv|读取图像(六十五)使用cv2.boundingRect()函数实现图像轮廓矩形标注-CSDN博客 这篇文章成功在图…...
嵌入式经常用到串口,如何判断串口数据接收完成?
说起通信,首先想到的肯定是串口,日常中232和485的使用比比皆是,数据的发送、接收是串口通信最基础的内容。这篇文章主要讨论串口接收数据的断帧操作。 空闲中断断帧 一些mcu(如:stm32f103)在出厂时就已经在…...
