news 2026/4/3 5:13:51

算法系列(Algorithm)- 快速排序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法系列(Algorithm)- 快速排序

1. 基本思想与核心原理

快速排序的核心思想是通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

该算法的基本步骤包括:

  1. 选择基准值(Pivot):从数组中选择一个元素作为基准值
  2. 分区操作(Partition):重新排列数组,使所有小于基准值的元素都放在基准值的左边,所有大于基准值的元素都放在基准值的右边
  3. 递归排序:对基准值左右两边的子数组递归地执行快速排序

2. 快速排序的详细实现步骤

2.1 分区操作详解

分区操作是快速排序算法的核心部分,其目标是将数组重新排列,使得所有小于基准值的元素位于基准值的左侧,所有大于基准值的元素位于基准值的右侧。

分区算法的具体过程

  1. 选择数组的最后一个元素作为基准值(pivot)
  2. 初始化两个指针:i指向较小元素的边界(初始为low-1),j用于遍历数组
  3. 遍历数组从low到high-1:
    • 如果当前元素小于等于基准值,将i指针右移一位,然后交换arr[i]和arr[j]
  4. 最后将基准值放到正确位置(i+1处)

2.2 递归排序过程

完成分区操作后,基准值已经处于其最终排序位置。此时,数组被分成两个子数组:

  • 左子数组:包含所有小于基准值的元素
  • 右子数组:包含所有大于基准值的元素

对这两个子数组分别递归地执行快速排序,直到子数组的大小为0或1(即已经有序)。

2.3 打个比喻

可以把快速排序想象成快速分类快递

  1. 选一个参考快递:比如选一个重量为1kg的快递作为参考
  2. 快速分堆:把所有小于1kg的放左边,大于1kg的放右边
  3. 每堆再分:对左边那堆,再选一个0.5kg的作为参考,继续分
  4. 直到分完:一直分到每堆只有一个快递,就全部排好序了

这个方法的聪明之处在于:不用一个个比较所有快递,而是通过选参考值快速分成两堆,大大减少了比较次数。

3. Java实现完整代码

以下是快速排序在Java中的标准实现,包含详细的注释说明:

import java.util.Arrays; public class QuickSort { /** * 快速排序的入口方法 * @param arr 待排序的数组 */ public static void quickSort(int[] arr) { if (arr == null || arr.length == 0) { return; } quickSort(arr, 0, arr.length - 1); } /** * 递归实现快速排序 * @param arr 待排序的数组 * @param low 子数组的起始索引 * @param high 子数组的结束索引 */ private static void quickSort(int[] arr, int low, int high) { if (low < high) { // 执行分区操作,获取基准值的正确位置 int pivotIndex = partition(arr, low, high); // 递归排序左子数组(基准值左边的元素) quickSort(arr, low, pivotIndex - 1); // 递归排序右子数组(基准值右边的元素) quickSort(arr, pivotIndex + 1, high); } } /** * 分区操作 - 快速排序的核心 * @param arr 待分区的数组 * @param low 分区起始索引 * @param high 分区结束索引 * @return 基准值的最终位置索引 */ private static int partition(int[] arr, int low, int high) { // 选择最后一个元素作为基准值(pivot) int pivot = arr[high]; // i指向较小元素的边界,初始为low-1 int i = low - 1; // 遍历数组,将小于基准值的元素移到左边 for (int j = low; j < high; j++) { if (arr[j] <= pivot) { i++; swap(arr, i, j); } } // 将基准值放到正确的位置(i+1) swap(arr, i + 1, high); // 返回基准值的最终位置 return i + 1; } /** * 交换数组中两个元素的位置 * @param arr 数组 * @param i 第一个元素的索引 * @param j 第二个元素的索引 */ private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } /** * 测试方法 */ public static void main(String[] args) { // 测试用例1:普通数组 int[] arr1 = {10, 7, 8, 9, 1, 5}; System.out.println("原始数组1: " + Arrays.toString(arr1)); quickSort(arr1); System.out.println("排序后数组1: " + Arrays.toString(arr1)); // 测试用例2:包含重复元素的数组 int[] arr2 = {3, 6, 8, 10, 1, 2, 1}; System.out.println("\n原始数组2: " + Arrays.toString(arr2)); quickSort(arr2); System.out.println("排序后数组2: " + Arrays.toString(arr2)); // 测试用例3:已排序数组 int[] arr3 = {1, 2, 3, 4, 5}; System.out.println("\n原始数组3: " + Arrays.toString(arr3)); quickSort(arr3); System.out.println("排序后数组3: " + Arrays.toString(arr3)); // 测试用例4:逆序数组 int[] arr4 = {5, 4, 3, 2, 1}; System.out.println("\n原始数组4: " + Arrays.toString(arr4)); quickSort(arr4); System.out.println("排序后数组4: " + Arrays.toString(arr4)); } }

4. 算法性能分析

4.1 时间复杂度分析

快速排序的时间复杂度取决于分区操作的质量:

  1. 最佳情况:每次分区都能将数组均匀分成两半,此时时间复杂度为O(n log n)
  2. 平均情况:在随机数据下,快速排序的平均时间复杂度也为O(n log n),这是其在实际应用中表现优异的主要原因
  3. 最坏情况:当每次分区都产生极度不平衡的分区时(例如数组已经有序或逆序),时间复杂度会退化到O(n²)

4.2 空间复杂度分析

快速排序是原地排序算法,不需要额外的存储空间来存储数据副本。其空间复杂度主要来自递归调用栈:

  • 最佳和平均情况:O(log n)(递归深度)
  • 最坏情况:O(n)(递归深度达到n)

4.3 稳定性分析

快速排序是一种不稳定的排序算法。在分区过程中,相等元素的相对位置可能会发生变化。

5. 快速排序的优化策略

虽然基本的快速排序算法已经相当高效,但在实际应用中还可以通过以下策略进行优化:

5.1 基准值选择优化

  1. 随机选择基准值:通过随机选择基准值,可以避免最坏情况的发生,提高算法的平均性能
  2. 三数取中法:选择数组的第一个、中间和最后一个元素的中位数作为基准值,可以减少分区不平衡的情况
  3. 随机化快速排序:在分区前随机交换一个元素到末尾作为基准值

5.2 小数组优化

当子数组的大小小于某个阈值(通常为10-20)时,可以使用插入排序代替快速排序。因为对于小数组,插入排序的常数因子更小,实际运行速度更快。

5.3 三路快速排序

对于包含大量重复元素的数组,可以使用三路快速排序(Three-way QuickSort)。它将数组分成三部分:小于基准值、等于基准值和大于基准值。这样可以避免对相等元素的重复比较和交换。

三路快速排序的实现示例:

public static void threeWayQuickSort(int[] arr, int low, int high) { if (low < high) { int[] pivotRange = threeWayPartition(arr, low, high); threeWayQuickSort(arr, low, pivotRange[0] - 1); threeWayQuickSort(arr, pivotRange[1] + 1, high); } }

6. 快速排序的应用场景

快速排序因其高效性而被广泛应用于各种场景:

  1. 大规模数据排序:快速排序的平均时间复杂度为O(n log n),在处理大规模数据时表现优异
  2. 数据库查询优化:在数据库系统中,快速排序常用于优化查询性能,特别是对需要排序的大量记录进行排序
  3. 数据分析与处理:在数据分析和统计领域,快速排序被用来快速对数据进行排序,以便进行后续的分析和处理
  4. 编程语言内置排序:许多编程语言的标准库中的排序函数都基于快速排序或其变体实现

7. 与其他排序算法的比较

7.1 与插入排序比较

  • 对于小规模数据(n < 20),插入排序通常更快
  • 快速排序在大规模数据上优势明显
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/9 21:41:34

SearchEngineJumpPlus终极指南:如何快速提升搜索效率的7个技巧

SearchEngineJumpPlus终极指南&#xff1a;如何快速提升搜索效率的7个技巧 【免费下载链接】SearchEngineJumpPlus 增强版搜索引擎跳转脚本&#xff0c;优化一些使用体验&#xff0c;Tampermonkey Userscript 项目地址: https://gitcode.com/GitHub_Trending/se/SearchEngine…

作者头像 李华
网站建设 2026/3/28 23:35:49

PyTorch Geometric中TUDataset加载问题全解析:从诊断到实战

PyTorch Geometric中TUDataset加载问题全解析&#xff1a;从诊断到实战 【免费下载链接】pytorch_geometric Graph Neural Network Library for PyTorch 项目地址: https://gitcode.com/GitHub_Trending/py/pytorch_geometric 当你在图神经网络项目中尝试加载TUDataset时…

作者头像 李华
网站建设 2026/3/11 10:37:15

精准匹配严苛标准,研发管理系统:筑牢汽车电子芯片研发管理核心竞争力——全星研发项目管理APQP软件系统应用解析

精准匹配严苛标准&#xff0c;研发管理系统&#xff1a;筑牢汽车电子芯片研发管理核心竞争力——全星研发项目管理APQP软件系统应用解析 汽车电子芯片半导体行业的研发工作&#xff0c;受IATF 16949、AEC-Q系列等严苛标准约束&#xff0c;兼具技术迭代快、流程链路长、风险管控…

作者头像 李华
网站建设 2026/3/27 20:56:42

SC7A20三轴加速度计完整开发指南:从寄存器配置到低功耗优化

SC7A20三轴加速度计完整开发指南&#xff1a;从寄存器配置到低功耗优化 【免费下载链接】SC7A20规格书带寄存器描述-中文详细资料 本仓库提供了士兰微电子出品的SC7A20三轴传感器的珍贵中文规格书&#xff0c;这是一份在业内难能可贵的资源。针对从事可穿戴设备、低功耗检测等领…

作者头像 李华
网站建设 2026/3/13 18:58:35

STUMPY时间序列分析库:解锁数据隐藏价值

STUMPY时间序列分析库&#xff1a;解锁数据隐藏价值 【免费下载链接】stumpy STUMPY is a powerful and scalable Python library for modern time series analysis 项目地址: https://gitcode.com/gh_mirrors/st/stumpy 项目概览与核心价值 STUMPY是一个专为时间序列分…

作者头像 李华
网站建设 2026/4/1 14:56:15

颠覆传统!2025年AI编程工具十大黑马出炉,第一名居然是它?

当传统程序员还在为代码逻辑绞尽脑汁时&#xff0c;2025年的AI编程工具已掀起一场效率革命&#xff01;从“代码补全”到“全栈生成”&#xff0c;从“工具辅助”到“智能代理”&#xff0c;十大黑马工具正以颠覆性技术重塑开发范式。 黑马榜首&#xff1a;Lynx——零代码时代…

作者头像 李华