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

详解快速排序

引言

快速排序(QuickSort)是一种分而治之的排序算法。它通过选择一个基准元素,将数组分为两部分,一部分的元素都比基准小,另一部分的元素都比基准大,然后对这两部分再进行快速排序,最终得到有序的数组。

算法思想

  1. 选择基准值(Pivot Selection):从数组中挑选一个元素作为基准值(Pivot)。基准值的选择方式多样,例如选择首个元素、末尾元素、中间元素或随机元素。

  2. 分区操作(Partitioning):重新排列数组,让所有小于基准值的元素位于基准值的左侧,所有大于基准值的元素位于基准值的右侧。这个过程被称作分区(Partition)。分区结束后,基准值就处于其最终排序后的位置。

  3. 递归排序(Recursive Sorting):分别对基准值左右两侧的子数组递归地应用上述两个步骤,直至子数组的大小为 0 或者 1,此时数组已完全有序。

算法分析

时间复杂度

  • 最优情况:当每次选择的基准元素正好将数组分成两等分时,快速排序的时间复杂度是O(nlogn)

  • 最坏情况:当每次选择的基准元素是最大或最小元素时,快速排序的时间复杂度是O(n^2)。

  • 平均情况:在平均情况下,快速排序的时间复杂度也是O(nlogn)

空间复杂度

快速排序的空间复杂度是O(logn),因为在递归调用中需要使用栈来存储中间结果。这意味着

在排序过程中,最多需要O(logn)的额外空间来保存递归调用的栈帧。

优化方案

  1. 选择合适的基准:选择合适的基准元素可以提高算法的性能。

  2. 三数取中;通过选择中间元素作为基准,可以避免最坏情况的出现。

  3. 分区的改进:可以使用双指针或其他方法来改进分区的过程,提高算法的效率。

  4. 小数组使用插入排序:对于小数组,可以直接使用插入排序,避免不必要的递归。

Java实现

/*** 交换数组中两个指定位置的元素* @param nums 待操作的数组* @param i    第一个元素的索引* @param j    第二个元素的索引*/
public void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;
}/*** 快速排序的分区函数,选择一个基准值并将数组分为两部分* 左边部分元素都小于等于基准值,右边部分元素都大于等于基准值* @param nums 待分区的数组* @param l    左边界索引* @param r    右边界索引* @return 基准值最终所在的索引位置*/
public int partition(int nums[], int l, int r) {// 随机选择一个索引作为基准值的位置,减少最坏情况的发生概率Random random = new Random();int index = l + random.nextInt(r - l + 1);// 将基准值交换到数组的左边界位置swap(nums, l, index);int i = l;          // 左指针,从左边界开始int j = r;          // 右指针,从右边界开始int x = nums[i];    // 基准值,此时位于左边界位置// 双指针扫描,将数组分为两部分while (i < j) {// 从右向左找第一个小于等于基准值的元素while (i < j && nums[j] > x) {j--;}// 将找到的元素交换到左边if (i < j) {swap(nums, i, j);i++;  // 左指针右移一位}// 从左向右找第一个大于等于基准值的元素while (i < j && nums[i] < x) {i++;}// 将找到的元素交换到右边if (i < j) {swap(nums, i, j);j--;  // 右指针左移一位}}// 返回基准值最终所在的位置return i;
}/*** 快速排序主函数,递归地对数组进行排序* @param nums 待排序的数组* @param l    左边界索引* @param r    右边界索引*/
public void quickSort(int nums[], int l, int r) {// 递归终止条件:当左边界大于右边界时,区间内没有元素或只有一个元素,已经有序if (l >= r) {return;}// 分区并获取基准值的位置int pivot = partition(nums, l, r);// 递归排序基准值左边的子数组quickSort(nums, l, pivot - 1);// 递归排序基准值右边的子数组quickSort(nums, pivot + 1, r);
}

http://www.lqws.cn/news/566821.html

相关文章:

  • SRS流媒体服务器(8)源码分析之rtc/rtmp互相转码详解
  • 数据可视化 - 单子图
  • 第10章 数组和指针
  • 左神算法之螺旋打印
  • SQL Server从入门到项目实践(超值版)读书笔记 19
  • 从GPTs到Real智能体:目前常见的几种创建智能体方式
  • spring:BeanPostProcessor后置处理器介绍
  • 小米路由器 AX3000T自定义子网掩码
  • Mybatis多条件查询设置参数的三种方法
  • stm32hal模块驱动(1)hpdl1414驱动
  • Vue的watch函数实现
  • 华为云 Flexus+DeepSeek 征文|华为云 Flexus 云服务 Dify-LLM 平台深度部署指南:从基础搭建到高可用实践
  • 智能制造——解读西门子数字化工厂规划报告(三年实施计划)【附全文阅读】
  • 机器学习在智能供应链中的应用:需求预测与库存优化
  • 大事件项目记录12-文章管理接口开发-总
  • 设计模式之适配器模式
  • OpenCV读取照片和可视化详解和代码示例
  • MySQL 安装使用教程
  • Java垃圾收集机制Test
  • PL-SLAM: Real-Time Monocular Visual SLAM with Points and Lines
  • Ai工具分享(2):Vscode+Cline无限免费的使用教程
  • XWPFDocument导出word文件
  • Linux中《动/静态库原理》
  • Redis缓存击穿深度解析:从现象到实战的完整解决方案
  • github上传代码步骤(http)
  • Cesium快速入门到精通系列教程十二:Cesium1.74中环绕地球生成​​经线环​​
  • Javaweb - 7 xml
  • 【智能协同云图库】智能协同云图库第三弹:基于腾讯云 COS 对象存储—开发图片模块
  • 日常 AI 工具汇总
  • Oracle 递归 + Decode + 分组函数实现复杂树形统计进阶(第二课)