【排序算法】快速排序详解--附详细流程代码

news2025/6/2 19:41:28

快速排序算法

介绍

快速排序(Quick Sort)是一种高效的分治排序算法,由英国计算机科学家 Tony Hoare 于 1960 年提出。它是实际应用中最常用的排序算法之一。快速排序的基本思想是:选择一个"基准"(pivot)元素,通过一次排序将待排序列分割成独立的两部分,一部分所有元素均小于基准,另一部分所有元素均大于基准,然后递归地对这两部分分别进行快速排序。分治策略的运用让快速排序在平均情况下能达到 O(nlogn) 的时间复杂度,大大优于简单排序算法的 O(n²) 性能。

算法步骤

  1. 从数列中选择一个元素作为"基准"(pivot),本文采用最左侧元素作为基准
  2. 将所有比基准值小的元素放到基准前面,所有比基准值大的元素放到基准后面(分区操作)
  3. 对基准左右两个子序列分别重复步骤1和2,直到子序列只有一个元素或为空

核心特性

  • 分治策略:将问题分解为更小的子问题,逐步解决
  • 原地排序:只需要 O(logn) 的额外空间复杂度(主要用于递归调用的栈空间)
  • 时间复杂度:平均情况为 O(nlogn),最坏情况为 O(n²),最好情况为 O(nlogn)
  • 不稳定性:相等元素的相对位置在排序后可能会改变
  • 高效性:在实际应用中,快速排序通常是最快的排序算法之一

基础实现

接下来大家一起看下快速排序的部分主流语言实现:

代码实现

Java实现

public class QuickSort {
    public 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);
        }
    }

    private static int partition(int[] arr, int low, int high) {

        int pivot = arr[low];
        int i = low + 1;

        for (int j = low + 1; j <= high; j++) {

            if (arr[j] < pivot) {

                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
                i++;
            }
        }


        int temp = arr[low];
        arr[low] = arr[i - 1];
        arr[i - 1] = temp;

        return i - 1;
    }


    public static void printArray(int[] arr) {
        for (int i : arr) {
            System.out.print(i + " ");
        }
        System.out.println();
    }


    public static void main(String[] args) {
        int[] arr = {10, 7, 8, 9, 1, 5};
        System.out.println("排序前的数组:");
        printArray(arr);

        quickSort(arr, 0, arr.length - 1);

        System.out.println("排序后的数组:");
        printArray(arr);
    }
}

注意,在上述代码里,通过:

for (int j = low + 1; j <= high; j++) {

    if (arr[j] < pivot) {

        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        i++;
    }
}

将小于基准的元素移到左侧,然后通过:

int temp = arr[low];
arr[low] = arr[i - 1];
arr[i - 1] = temp;

修正基准的位置,实现基准左侧都小于基准、基准右侧大于等于基准。

优化策略

随机选择基准元素

使用最左侧元素作为基准可能会在数组已经排序或接近排序时导致最坏性能,随机选择基准可以降低这种风险:

private static int randomPartition(int[] arr, int low, int high) {

    int randomIndex = low + (int)(Math.random() * (high - low + 1));


    int temp = arr[randomIndex];
    arr[randomIndex] = arr[low];
    arr[low] = temp;


    return partition(arr, low, high);
}

三数取中法

选择左端、中间和右端三个元素的中值作为基准,可以进一步优化快速排序:

private static int medianOfThreePartition(int[] arr, int low, int high) {
    int mid = low + (high - low) / 2;


    if (arr[mid] < arr[low])
        swap(arr, mid, low);
    if (arr[high] < arr[low])
        swap(arr, high, low);
    if (arr[high] < arr[mid])
        swap(arr, high, mid);


    swap(arr, mid, low);


    return partition(arr, low, high);
}

优缺点

优点

  • 平均情况下非常高效,时间复杂度为 O(nlogn)
  • 原地排序,空间复杂度低
  • 缓存友好,数据局部性好
  • 适合处理大规模数据
  • 在许多实际应用中表现优秀

缺点

  • 最坏情况下性能退化至 O(n²),比如当数组已经排序时
  • 不稳定的排序算法
  • 对于小数组,快速排序可能比其他基础排序慢
  • 递归实现可能导致栈溢出(可以使用迭代方式解决)

应用场景

  • 需要高效排序大量数据的情况
  • 作为系统库中的排序函数(如 C++ 的 std::sort、Java 的 Arrays.sort)
  • 需要就地排序且对空间复杂度敏感的场景
  • 需要平均情况下高性能的应用

扩展

双轴快速排序

Java 的 Arrays.sort() 使用的是双轴快速排序,它使用两个枢轴(基准),可以进一步提高性能:

public static void dualPivotQuickSort(int[] arr, int low, int high) {
    if (high <= low) return;


    if (arr[low] > arr[high]) {
        int temp = arr[low];
        arr[low] = arr[high];
        arr[high] = temp;
    }


    int pivot1 = arr[low];
    int pivot2 = arr[high];

    int lt = low + 1;    
    int gt = high - 1;   
    int i = low + 1;     

    while (i <= gt) {

        if (arr[i] < pivot1) {
            int temp = arr[lt];
            arr[lt] = arr[i];
            arr[i] = temp;
            lt++;
            i++;
        } 

        else if (arr[i] > pivot2) {
            int temp = arr[i];
            arr[i] = arr[gt];
            arr[gt] = temp;
            gt--;
        } 

        else {
            i++;
        }
    }


    arr[low] = arr[lt - 1];
    arr[lt - 1] = pivot1;

    arr[high] = arr[gt + 1];
    arr[gt + 1] = pivot2;


    dualPivotQuickSort(arr, low, lt - 2);
    dualPivotQuickSort(arr, lt, gt);
    dualPivotQuickSort(arr, gt + 2, high);
}

测验

这里准备了一些测试题,方便大家判断自己的掌握情况:

  1. 快速排序的平均时间复杂度是多少?
  2. 快速排序是稳定的排序算法吗?
  3. 使用最左侧元素作为基准的快速排序在什么情况下会出现最坏性能?
  4. 快速排序的空间复杂度是多少?为什么?

测验答案

  1. O(nlogn)。
  2. 不是,因为基准元素的移动可能会改变相等元素的相对位置。
  3. 当数组已经排序或接近排序时,每次分区只能减少一个元素,时间复杂度退化为O(n²)。
  4. O(logn),主要是递归调用占用的栈空间,最坏情况下为O(n)。

相关的 LeetCode 热门题目

给大家推荐一些可以用来练手的 LeetCode 题目:

  • 215. 数组中的第K个最大元素 - 可以使用快速选择算法(快速排序的变体)求解,练习分区思想
  • 912. 排序数组
  • 75. 颜色分类 - 一个经典的荷兰国旗问题,可以使用类似快速排序的分区思想解决

来自: 快速排序 - 算法导航

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2394585.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决各个系统报错TDengine:no taos in java.library.path问题

windows 系统解决办法 在本地上安装一个TD的Windows客户端&#xff0c;注意安装的客户端版本一定要和服务端TD版本完全一致。&#xff08;或者将 C:\TDengine\driver\taos.dll 拷贝到 C:\Windows\System32\ 目录下&#xff09; 客户端各个历史版本下载链接&#xff1a;TDengin…

java helloWord java程序运行机制 用idea创建一个java项目 标识符 关键字 数据类型 字节

HelloWord public class Hello{public static void main(String[] args) {System.out.print("Hello,World!");} }java程序运行机制 用idea创建一个java项目 建立一个空项目 新建一个module 注释 标识符 关键字 标识符注意点 数据类型 public class Demo02 {public st…

免费文本转语音工具体验:祈风TTS使用

简介&#xff1a;语音生成的另一种方式 现在很多人通过视频记录生活&#xff0c;表达观点。拍摄剪辑不难&#xff0c;配音成了常见难题。部分人对自己的声音不够自信&#xff0c;也有人在特定场景下不便出声。文本转语音工具可以成为解决方案。 常见的TTS&#xff08;Text To…

JS和TS的区别

JavaScript 与 TypeScript 的主要区别和特性对比 1. 基础定义 JavaScript 是一种动态、弱类型的编程语言&#xff0c;广泛应用于前端开发以及通过 Node.js 扩展到后端开发。TypeScript 则是 JavaScript 的超集&#xff0c;它在 JavaScript 的基础上添加了静态类型系统和其他增…

Python实现P-PSO优化算法优化BP神经网络分类模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 随着人工智能技术的快速发展&#xff0c;神经网络在分类任务中展现了强大的性能。BP&#xff08;Back Propagation&…

Linux --进度条小程序更新

这里使用随机数来模拟下载量&#xff0c;来实现一个下载进度更新的小程序 main.c 的代码&#xff0c;其中downlod这个函数使用的是函数指针&#xff0c;如果有多个进度条函数可以传入进行多样化的格式下载显示&#xff0c;还需要传入一个下载总量&#xff0c;每次"下载以…

关于镜像如何装进虚拟机

本篇文章为感谢小仙猪老师特别编写 本篇文章仅以Ubuntu为例 目录 创建虚拟机 汉化 如果没有China选项 检查网络 创建虚拟机 第一步&#xff0c;创建虚拟机 因为&#xff0c;第一个选项是会把虚拟机的文件放在c盘因此&#xff0c;这里博主选择自定义&#xff0c;然后下一…

智慧体育馆数字孪生,场馆管理智能化

图扑数字孪生智慧体育馆可视化管理平台。通过高精度三维建模&#xff0c;对体育馆建筑结构、设施设备等进行 1:1 虚拟映射&#xff0c;全方位还原场馆物理实体。系统集成多维度传感器数据&#xff0c;实现对人流量、客流密度、区域拥堵指数等信息的实时采集与分析&#xff0c;动…

回归算法模型之线性回归

哈喽&#xff01;我是 我不是小upper&#xff5e; 今天来和大家聊聊「线性回归」—— 这是机器学习里最基础、最直观的算法之一&#xff0c;咱们用一个超简单的例子就能搞懂它&#xff01; 先看一个生活场景 假设你是房产中介&#xff0c;遇到一个灵魂拷问&#xff1a; 客户有…

【深度学习】10. 深度推理(含链式法则详解)RNN, LSTM, GRU,VQA

深度推理&#xff08;含链式法则详解&#xff09;RNN, LSTM, GRU&#xff0c;VQA RNN 输入表示方式 在循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;中&#xff0c;我们处理的是一段文字或语音等序列数据。对于文本任务&#xff0c;输入通常是单词序列…

【Qt】Bug:findChildren找不到控件

使用正确的父对象调用 findChildren&#xff1a;不要在布局对象上调用 findChildren&#xff0c;而应该在布局所在的窗口或控件上调用。

【linux】linux进程概念(四)(环境变量)超详细版

小编个人主页详情<—请点击 小编个人gitee代码仓库<—请点击 linux系列专栏<—请点击 倘若命中无此运&#xff0c;孤身亦可登昆仑&#xff0c;送给屏幕面前的读者朋友们和小编自己! 目录 前言一、基本概念二、认识常见的几个环境变量echo $ 查看某个环境变量env 显示…

从零开始的二三维CAD|CAE软件: 解决VTK,DICOM体素化-失效问题.

背景: 在从零开始的二三维软件开发中, 需要加载CT的dicoms影像文件, 并将其序列化之后的数据,体素化 可惜..vtk的c#库,将其体素化的时候,竟然失败... 使用vtkDicomReader ,设置 Dicom文件夹读取,竟然不停的失败...从网上找了一些版本.也没啥可用的资料... 解决办法: 直接…

【计算机网络】应用层协议Http——构建Http服务服务器

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;计算机网络 &#x1f339;往期回顾&#x1f339;&#xff1a; 【Linux笔记】——进程间关系与守护进程 &#x1f516;流水不争&#xff0c;争的是滔滔不息 一、Http协…

linux版本vmware修改ubuntu虚拟机为桥接模式

1、先打开linux版本vmware操作界面 2、设置虚拟路由编辑器的桥接模式 输入账号密码 自动模式 不需要进行任何操作 3、修改虚拟机设置网络模式为桥接模式 然后save保存一下配置 4、现在进入虚拟机查看ens33配置 网卡启动但是没有ip 5、自己进行设置修改ubuntu网络配置文件 cd …

从0到1上手Trae:开启AI编程新时代

摘要&#xff1a;字节跳动 2025 年 1 月 19 日发布的 Trae 是一款 AI 原生集成开发环境工具&#xff0c;3 月 3 日国内版推出。它具备 AI 问答、代码自动补全、基于 Agent 编程等功能&#xff0c;能自动化开发任务&#xff0c;实现端到端开发。核心功能包括智能代码生成与补全、…

Linux之MySQL安装篇

1.确保Yum环境是否能正常使用 使用yum环境进行软件的安装 yum -y install mysql-server mysql2.确保软件包已正常完成安装 3.设置防火墙和selinux配置 ## 关闭防火墙 systemctl stop firewalld## 修该selinux配置 vim /etc/selinux/config 将seliuxenforcing修改为sel…

Asp.Net Core 如何配置在Swagger中带JWT报文头

文章目录 前言一、配置方法二、使用1、运行应用程序并导航到 /swagger2、点击右上角的 Authorize 按钮。3、输入 JWT 令牌&#xff0c;格式为 Bearer your_jwt_token。4、后续请求将自动携带 Authorization 头。 三、注意事项总结 前言 配置Swagger支持JWT 一、配置方法 在 …

第12讲、Odoo 18 权限控制机制详解

目录 引言权限机制概述权限组&#xff08;Groups&#xff09;访问控制列表&#xff08;ACL&#xff09;记录规则&#xff08;Record Rules&#xff09;字段级权限控制按钮级权限控制菜单级权限控制综合案例&#xff1a;多层级权限控制最佳实践与注意事项总结 引言 Odoo 18 提…

8086 处理器 Flags 标志位全解析:CPU 的 “晴雨表” 与 “遥控器”总结:

引入&#xff1a; 你是否好奇&#xff0c;当 CPU 执行一条加法指令时&#xff0c;如何自动判断结果是否超出范围&#xff1f;当程序跳转时&#xff0c;如何快速决定走哪条分支&#xff1f;甚至在调试程序时&#xff0c;为何能让 CPU “一步一停”&#xff1f;这一切的答案&…