当前位置: 首页 > news >正文

数据结构——快速排序

快速排序

在交换排序中,快速排序是效率极高的一种,它基于“分治法”思想,通过选择一个“基准元素”将数组分成两部分,再递归处理这两部分,最终实现整个数组的有序排列。这种排序方式的核心是“一趟划分”——每完成一次划分,基准元素会被放到最终的正确位置,左边的元素都比基准小,右边的元素都比基准大,后续只需递归处理左右子数组即可。

1. 快速排序的核心思想与执行流程

快速排序的核心逻辑可概括为“选基准、做划分、递归根”,具体步骤如下:

  • 选基准:从待排序数组中选择一个元素作为“基准”(常见选择是数组第一个元素、最后一个元素或中间元素);
  • 做划分:通过左右指针移动,将数组分成两部分——左部分所有元素小于基准,右部分所有元素大于基准,基准元素放在两部分中间的最终位置;
  • 递归根:递归地对左部分和右部分重复“选基准、做划分”的过程,直到子数组的长度为1(此时子数组已有序)。

我们以数组arr = {49, 38, 65, 97, 76, 13, 27, 49}为例,详细展示快速排序的执行流程(选择数组第一个元素49作为基准):

  • 初始数组[49, 38, 65, 97, 76, 13, 27, 49](待排序区间:0~7)

  • 第一趟划分(确定基准49的位置)

    1. 初始化左指针i=0(指向基准),右指针j=7,基准值pivot=49
    2. 右指针j向左移动,找第一个小于基准的元素:j=6时元素27<49,停止移动,将arr[j](27)放到arr[i](0位置),数组变为[27, 38, 65, 97, 76, 13, 27, 49]i++(i=1);
    3. 左指针i向右移动,找第一个大于基准的元素:i=2时元素65>49,停止移动,将arr[i](65)放到arr[j](6位置),数组变为[27, 38, 65, 97, 76, 13, 65, 49]j--(j=5);
    4. 重复步骤2-3:右指针j=5时元素13<49,放到arr[i](2位置),数组变为[27, 38, 13, 97, 76, 13, 65, 49]i++(i=3);左指针i=3时元素97>49,放到arr[j](5位置),数组变为[27, 38, 13, 97, 76, 97, 65, 49]j--(j=4);
    5. 继续移动:右指针j=4时元素76>49,j--(j=3),此时i==j(i=3,j=3),将基准值49放到arr[i](3位置),划分结束。
      第一趟划分后,数组变为[27, 38, 13, 49, 76, 97, 65, 49],基准49在位置3,左子数组(0~2):[27, 38, 13],右子数组(4~7):[76, 97, 65, 49]
  • 递归处理左子数组(0~2)
    选基准27,划分后左子数组(00):`[27]`(有序),右子数组(22):[13](经划分后有序),最终左子数组变为[13, 27, 38]

  • 递归处理右子数组(4~7)
    选基准76,划分后左子数组(4~6):[65, 49](经递归划分后变为[49, 65]),右子数组(7~7):[97](有序),最终右子数组变为[49, 65, 76, 97]

  • 最终有序数组:合并左右子数组和基准,得到[13, 27, 38, 49, 49, 65, 76, 97]

2. 快速排序的代码实现

快速排序的代码核心是“一趟划分函数”和“递归排序函数”,以下是基于左指针基准的C语言实现,代码精简且注释详细:

// 一趟划分:返回基准最终位置,左小右大
int Partition(int arr[], int low, int high) {int pivot = arr[low]; // 选左端点为基准while (low < high) {// 右指针找小于基准的元素while (low < high && arr[high] >= pivot) high--;arr[low] = arr[high]; // 放到左指针位置// 左指针找大于基准的元素while (low < high && arr[low] <= pivot) low++;arr[high] = arr[low]; // 放到右指针位置}arr[low] = pivot; // 基准归位return low; // 返回基准位置
}// 快速排序:递归处理左右子数组
void QuickSort(int arr[], int low, int high) {if (low < high) { // 子数组长度>1才处理int pivotPos = Partition(arr, low, high); // 划分QuickSort(arr, low, pivotPos-1); // 左子数组QuickSort(arr, pivotPos+1, high); // 右子数组}
}

代码说明:

  • Partition函数:实现一趟划分,通过左右指针交替移动,将小于基准的元素移到左边,大于基准的移到右边,最后返回基准位置;
  • QuickSort函数:递归调用,若子数组区间low < high(长度大于1),则先划分,再递归处理左(low~pivotPos-1)、右(pivotPos+1~high)子数组。
3. 快速排序的性能与特性
  • 时间复杂度

    • 最好情况(每次划分均匀,左右子数组长度接近):每趟划分处理n个元素,递归深度为logn,总时间复杂度为O(nlogn)
    • 最坏情况(数组有序,选两端为基准,划分后一边为空):递归深度为n,总时间复杂度为O(n²)
    • 平均情况:通过随机选择基准可避免最坏情况,平均时间复杂度为O(nlogn),是所有O(nlogn)排序算法中实际运行速度较快的一种。
  • 空间复杂度:空间开销来自递归栈,最好/平均递归深度为logn,空间复杂度O(logn);最坏递归深度为n,空间复杂度O(n),属于“原地排序”(无额外数组开销)。

  • 稳定性:划分过程中,相同元素可能被交换到基准两侧(如示例中的两个49),相对顺序改变,因此快速排序是不稳定的排序算法。

4. 适用场景

快速排序适合以下场景:

  • 数据量较大的无序数组(如n>1000):O(nlogn)的平均时间复杂度能保证高效处理;
  • 对排序速度要求高,且不要求稳定性的场景(如普通数据统计、非业务关键数据排序);
  • 内存资源有限的场景:原地排序特性可减少内存开销。

综上,快速排序通过分治法和一趟划分,实现了高效的排序,核心是“基准归位+递归处理”。虽然存在最坏情况,但通过合理选择基准(如随机基准、三数取中)可大幅降低最坏情况概率,使其成为实际应用中最常用的排序算法之一。理解一趟划分的指针移动逻辑和递归流程,是掌握快速排序的关键。

http://www.dtcms.com/a/524507.html

相关文章:

  • IntelliJ IDEA新版下载、安装、创建项目及Maven配置的教程(附安装包等)
  • C++特性详解:extern、缺省参数、函数模板与名字空间
  • VUE+Electron从0开始搭建开发环境
  • MongoDB 平替新方案:金仓多模数据库驱动电子证照国产化落地
  • 项目(一)
  • SaaS多租户架构实践:字段隔离方案(共享数据库+共享Schema)
  • 企业网站网页设计的步骤房地产网站建设需求说明书
  • 中国专门做生鲜的网站著名品牌展厅设计
  • 开发避坑指南(66):IDEA 2025 Gradle构建安全协议警告:Maven仓库HTTPS切换或允许HTTP的配置方法
  • 前端新手入门-HBuilder工具安装
  • AceContainer::Initialize()函数的分析
  • 石家庄网站建设方案咨询涉县住房与城乡建设厅网站
  • 鸿蒙Next媒体开发全攻略(ArkTS):播放、录制、查询与转码
  • vs2015网站开发基础样式福田庆三下巴
  • Hugging Face介绍
  • 要建立网站和账号违法违规行为数据库和什么黑名单企业所得税优惠税率
  • 大模型训练中的关键技术与挑战:数据采集、微调与资源优化
  • 【文献笔记】arXiv 2018 | PointSIFT
  • 如何检测和解决I2C通信死锁
  • 深度学习快速入门手册
  • 如何看待 AI 加持下的汽车智能化?带来更好体验的同时能否保证汽车安全?
  • Linux中的一些常见命令
  • 三步将AI模型转换为 DeepX 格式并完成精度评估
  • 做第一个网站什么类型天津市建筑信息平台
  • 找一个网站做优化分析app界面设计属于什么设计
  • 【开题答辩全过程】以 毕业设计选题系统的设计与实现为例,包含答辩的问题和答案
  • 语言基础再谈
  • 网站后台用什么开发网页制作怎么做多个网站
  • 每周读书与学习->JMeter主要元件详细介绍(二)函数助手
  • asp网站开发技术免费建网站模板平台