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

快速排序C++模板,面试常考需背熟

快速排序介绍

快速排序(Quick Sort)是计算机科学领域中极为经典且高效的一种排序算法,它在众多实际应用场景中都发挥着重要作用。该算法由英国杰出的计算机科学家托尼·霍尔(Tony Hoare)于1960年提出,自诞生以来,因其卓越的性能而被广泛应用于各种数据排序任务中。

基本思想

快速排序巧妙地运用了分治法(Divide and Conquer)的策略。分治法的核心概念是将一个复杂的大问题分解为若干个规模较小、相互独立且与原问题形式相同的子问题,接着递归地去解决这些子问题,最后把各个子问题的解合并起来,从而得到原问题的解。在快速排序的实现过程中,就是把一个数组划分成两个子数组,然后分别对这两个子数组进行排序操作。

具体步骤
选择基准点(Pivot)

基准点的选择在快速排序里是一个至关重要的步骤,它直接影响到后续分区操作的效果以及整个算法的性能表现。基准点可以从数组中的任意位置选取,常见的选择方式有以下几种:

  • 选择数组的第一个元素:这种方式实现起来较为简单,但在某些特殊情况下,比如数组已经有序或者接近有序时,可能会导致算法性能下降。
  • 选择数组的最后一个元素:同样实现简单,但也存在与选择第一个元素类似的性能风险。
  • 选择数组的中间元素:选择中间元素作为基准点能够在一定程度上避免最坏情况的发生,使得分区操作更加均匀地将数组分成两部分。
  • 随机选择元素:随机选择基准点可以有效地避免某些特定输入导致的最坏情况,提高算法的平均性能。
分区操作(Partitioning)

分区操作是快速排序的核心环节,其目标是对数组中的元素进行重新排列,让所有小于基准点的元素都位于基准点的左侧,所有大于基准点的元素都位于基准点的右侧。这一过程通常借助双指针来完成,一个指针从数组的左侧开始向右移动,另一个指针从数组的右侧开始向左移动,当两个指针相遇时,分区操作就宣告结束。

递归排序

完成分区操作之后,数组会被划分成两个子数组,分别是基准点左侧的子数组和基准点右侧的子数组。对这两个子数组分别递归地应用快速排序算法,直至子数组的长度为1或0。因为长度为1或0的数组本身已经是有序的,无需再进行排序。
在这里插入图片描述

复杂度分析
时间复杂度

快速排序的平均时间复杂度为 (O(n log n))。在平均情况下,每次分区操作都能够将数组大致均匀地分成两个相等的子数组,递归的深度为 (log n),而每次分区操作需要遍历数组中的所有元素,时间复杂度为 (O(n))。不过,在最坏情况下,例如当数组已经有序或者接近有序时,每次选择的基准点恰好是数组中的最大或最小元素,此时时间复杂度会退化为 (O(n^2))。

空间复杂度

快速排序的空间复杂度主要取决于递归调用栈的深度。平均情况下,递归调用栈的深度为 (O(log n)),因此空间复杂度为 (O(log n))。在最坏情况下,递归调用栈的深度为 (O(n)),空间复杂度也会相应地变为 (O(n))。

稳定性

快速排序是一种不稳定的排序算法,这意味着在排序过程中,相等元素的相对顺序可能会发生改变。例如,对于数组 ([3, 2, 3, 1]),排序后两个值为3的元素的相对顺序可能与排序前不同。

应用场景

由于快速排序具备较高的平均性能,所以在大多数场景下都能有出色的表现。它广泛应用于需要对大规模数据进行排序的场景,比如数据库查询结果的排序、大规模数据集的预处理等。此外,快速排序也是许多编程语言标准库中排序函数的实现基础,像Python的 sorted() 函数、Java的 Arrays.sort() 函数等在底层实现时都借鉴了快速排序的思想。

快速排序流程图

开始
选择基准元素
分区操作
左子数组是否为空
对左子数组快速排序
右子数组是否为空
对右子数组快速排序
结束

快速排序代码

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;
    int x = q[(l + r) / 2];
    // 初始化双指针i和j,i从左侧开始,j从右侧开始,注意i和j都往外扩一个,避免边界错误
    int i = l - 1;
    int j = r + 1;

    // 使用while循环进行元素的交换,直到i和j相遇
    while (i < j)
    {
        // 从左向右扫描,找到第一个大于等于基准点x的元素
        do i++; while (q[i] < x);

        // 从右向左扫描,找到第一个小于等于基准点x的元素
        do j--; while (q[j] > x);

        // 如果i小于j,说明找到了一对可以交换的元素
        if (i < j) swap(q[i], q[j]);
    }

    // 递归地对子数组进行快速排序,注意递归的边界是j,因为j已经移动到了第一个大于x的元素位置
    quick_sort(q, l, j); //j

    // 对于j+1到r的子数组,同样递归地进行快速排序
    quick_sort(q, j + 1, r);
}

// 调用方法:quick_sort(q, 0, q.size() - 1);


http://www.kler.cn/a/552380.html

相关文章:

  • 初探ai利用图片生成前端代码
  • 无人机飞手培训机构招生宣传技术详解
  • langchain本地知识库问答机器人集成本地知识库
  • vue前端可视化大屏页面适配方案
  • torch使用心得
  • pyqt 调用颜色选择器
  • 蚁剑(AutSword)的下载安装与报错解决
  • 【git】通过 rebase 合并分支
  • Python高级语法之urllib
  • MAVSDK - Custom Mavlink处理
  • 【笔记】linux离线部署Ollama+Deepseek r1+open webui
  • 本地 Ollama 部署 Deepseek R1 并使用 Spring AI Alibaba 构建 Chat 应用示例
  • STM32 HAL库 UART串口发送数据实验
  • 华为交换机trunk简介配置
  • POI优化Excel录入
  • Node.js 中 morgan 依赖详解
  • 使用iOS个人声音与SoVITS训练个人AI语音(10分钟快速上手)
  • Linux上部署Java项目-通过sh脚本启动
  • Day01 【苍穹外卖】环境搭建与前后端联调
  • MySQL 面试系列:MySQL 事务的面试题总结