【十大排序算法】快速排序

news2024/11/29 0:38:04

在乱序的世界中,快速排序如同一位智慧的园丁,
以轻盈的手法,将无序的花朵们重新安排,
在每一次比较中,沐浴着理性的阳光,
终使它们在有序的花园里,开出绚烂的芬芳。

文章目录

  • 一、快速排序
  • 二、发展历史
  • 三、处理流程
  • 四、算法实现
  • 五、快速排序的特性
  • 六、小结
  • 推荐阅读

一、快速排序

快速排序是一种高效的排序算法,它采用了分治的策略。它的基本思想是选择一个基准值,将数组分为两个子数组,一个子数组中的所有元素都小于基准值,另一个子数组中的所有元素都大于基准值,然后对这两个子数组递归地进行排序。

具体来说,快速排序的步骤如下:

  1. 选择一个基准值(通常是数组的第一个元素、最后一个元素或者中间元素)。
  2. 将数组分为两个子数组,一个子数组中的所有元素都小于基准值,另一个子数组中的所有元素都大于基准值。
  3. 对这两个子数组递归地进行排序。
  4. 将排好序的子数组合并起来,即得到有序数组。

快速排序的关键在于分割操作,通过这个操作,它可以将一个大问题分解成两个规模较小的子问题,然后分别解决,最终达到整体有序的目的。

二、发展历史

快速排序是由英国计算机科学家 Tony Hoare 1960 1960 1960 年代提出的。Hoare 最初将这一算法称为 “分区交换排序”,后来更广泛地称为快速排序。他的灵感来自于合并排序和插入排序。

  1. 早期思想: Hoare 注意到合并排序在实践中性能良好,但需要额外内存空间;而插入排序则内存消耗较少,但在大规模数据下性能不佳。他希望能够结合两者的优点,创造出一种既能够节省空间又能够在平均情况下具有良好性能的排序算法。
  2. Hoare 分区法: Hoare 提出了一种称为 Hoare 分区法的分区策略,这成为了快速排序的核心部分。这个方法从数组中选择一个基准值,将数组分成两个部分,左边的部分包含比基准值小的元素,右边的部分包含比基准值大的元素。然后,递归地对这两个部分进行排序。
  3. 论文发表: Hoare 在 1961 1961 1961 年发表了关于快速排序的论文,论文中描述了这一算法的基本原理和实现方法。此后,他不断改进和优化这一算法,使得快速排序成为了一种非常高效的排序算法。
  4. 持续优化: 随着计算机科学的发展,许多学者对快速排序进行了进一步的优化和改进。例如,采用随机化的方式选择基准值,以防止最坏情况的发生;使用三数取中法来选择基准值,以提高算法的稳定性和性能等。
  5. 现代应用: 至今,快速排序仍然是一种非常流行和高效的排序算法,被广泛应用于各种编程语言和实际应用中。其简洁而优雅的设计理念以及优秀的性能使得它成为了排序算法中的经典之作。

三、处理流程

场景假设:我们需要将下列无序序列使用快速排序按从小到大进行排序。
workspace.png
快速排序的流程如下:

  1. 在原序列中选取第一个元素 3 3 3 作为 Pivot 哨兵
  2. 将序列中小于 Pivot 的元素,放在 Pivot 的左边,大于 Pivot 的元素放在 Pivot 的右边
  3. 递归处理 Pivot 左边的序列和右边的序列
  4. 当子序列为长度 1 1 1 时终止

workspace (1).png

四、算法实现

// 快速排序入口
void quickSort(int[] arr, int low, int high) {
    if (low < high) {
        // 对数组进行分区操作
        int pivot = partition(arr, low, high);
        // 递归排序左半部分
        quickSort(arr, low, pivot - 1);
        // 递归排序右半部分
        quickSort(arr, pivot + 1, high);
    }
}

// 分区操作
int partition(int[] arr, int low, int high) {
    // 选择最后一个元素作为 pivot
    int pivot = arr[high];
    int i = low - 1; // 指向小于 pivot 的区域的边界

    // 遍历数组,将小于 pivot 的元素放到左侧
    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            // 交换元素
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }

    // 将 pivot 放到正确位置
    int temp = arr[i + 1];
    arr[i + 1] = arr[high];
    arr[high] = temp;

    // 返回 pivot的位置
    return i + 1;
}

public static void main(String[] args) {
    int[] arr = {5, 3, 8, 6, 2, 7, 1, 4};
    // 调用快速排序算法
    quickSort(arr, 0, arr.length - 1);

    // 输出排序后的数组
    System.out.print("Sorted array: ");
    for (int num : arr) {
        System.out.print(num + " ");
    }
}

算法时间复杂度分析:

情况时间复杂度计算公式公式解释
最好情况 O ( n l o g n ) O(nlogn) O(nlogn) T ( n ) = 2 T ( n 2 ) + n T(n) = 2T(\frac{n}{2}) + n T(n)=2T(2n)+n在最优情况下,每次划分都能将数组均匀地分成两部分。因此,我们有两个大小为 n 2 \frac{n}{2} 2n 的子问题,所以有 2 T ( n 2 ) 2T(\frac{n}{2}) 2T(2n)。然后,我们需要 n n n 的时间来进行划分操作。所以,总的时间复杂度就是 2 T ( n 2 ) + n 2T(\frac{n}{2}) + n 2T(2n)+n
平均情况 O ( n l o g n ) O(nlogn) O(nlogn) T ( n ) = T ( n 2 ) + T ( n 2 ) + n T(n) = T(\frac{n}{2}) + T(\frac{n}{2}) + n T(n)=T(2n)+T(2n)+n在平均情况下,我们假设每次划分都能将数组均匀地分成两部分。因此,我们有两个大小为 n 2 \frac{n}{2} 2n 的子问题,所以有 T ( n 2 ) + T ( n 2 ) T(\frac{n}{2}) + T(\frac{n}{2}) T(2n)+T(2n)。然后,我们需要 n n n 的时间来进行划分操作。所以,总的时间复杂度就是 T ( n 2 ) + T ( n 2 ) + n T(\frac{n}{2}) + T(\frac{n}{2}) + n T(2n)+T(2n)+n
最坏情况 O ( n 2 ) O(n^2) O(n2) T ( n ) = T ( n − 1 ) + n T(n) = T(n - 1) + n T(n)=T(n1)+n在最坏情况下,每次划分只能将数组划分为一份有 n − 1 n - 1 n1 个元素,另一份有 0 0 0 个元素。因此,我们有一个大小为 n − 1 n - 1 n1 子问题,所以有 T ( n − 1 ) T(n - 1) T(n1)。然后,我们需要 n n n 的时间来进行划分操作。所以,总的时间复杂度就是 T ( n − 1 ) + n T(n - 1) + n T(n1)+n

五、快速排序的特性

快速排序具有以下特性:

  1. 稳定性: 在一般情况下,快速排序是不稳定的,即相同元素在排序后可能会改变相对位置。
  2. 原地性: 快速排序是一种原地排序算法,不需要额外的辅助空间,只需要使用原始数组进行排序。
  3. 适应性: 快速排序适用于各种数据类型,并且对部分有序的数据排序效果良好。
  4. 高效性: 快速排序在平均情况下具有 O ( n l o g n ) O(nlogn) O(nlogn) 的时间复杂度,使其成为处理大规模数据的理想选择。

六、小结

快速排序是一种非常重要且高效的排序算法,适用于各种数据类型和应用场景。其原地性、高效性以及简单直观的实现使得它成为了排序算法中的经典之作。

推荐阅读

  1. Spring 三级缓存
  2. 深入了解 MyBatis 插件:定制化你的持久层框架
  3. Zookeeper 注册中心:单机部署
  4. 【JavaScript】探索 JavaScript 中的解构赋值
  5. 深入理解 JavaScript 中的 Promise、async 和 await

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

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

相关文章

Mysql 中的case-when

什么是 case-when case-when 是一种 sql 语句中的语法结构,结构如下&#xff1a; case 字段名 when 值 then 字段名|值 ... else 字段名|值 end case when 主要用于数据的 行列转换&#xff08;把一列数据转换为多列&#xff09; 前置条件&#xff1a; -- 表…

Linux网络 - json,网络计算服务器与客户端改进

文章目录 前言一、json1.引入库2. 使用步骤2.Calculator.hpp3.Task.hpp4.serverCal.hpp 新客户端 前言 本章内容主要对上一章的网络计算器客户端和服务器进行一些Bug修正与功能改进。 并学习如何使用json库和daemon函数。 一、json 在我们自己的电脑上一些软件的文件夹中&…

Unity编辑器扩展,快捷键的使用

代码部分 编辑器界面 使用方法&#xff1a; 使用方法和如图1一样&#xff0c;只需要在Menuitem的路径后面加上标识符号就行。 "#"对应的是shift "&"对应的是Alt "%"对应的是ctrl 比如我图中的是&#xff0c;%#s对应的是CtrlShifts&…

聚醚醚酮(Polyether Ether Ketone)PEEK在粘接使用时使用UV胶水的优势有哪些?要注意哪些事项?

聚醚醚酮&#xff08;Polyether Ether Ketone&#xff09;PEEK在粘接使用时使用UV胶水的优势有哪些&#xff1f;要注意哪些事项&#xff1f; 使用UV胶水在聚醚醚酮&#xff08;Polyether Ether Ketone&#xff0c;PEEK&#xff09;上进行粘接可能具有一些优势&#xff0c;但同时…

11-数组与指针深入理解——题型理解

11-数组与指针深入理解——题型理解 文章目录 11-数组与指针深入理解——题型理解一、理解题1二、理解题二三、理解题三四、理解题四五、理解题五六、理解题六 一、理解题1 #include <stdio.h>int main(void) {int (*p)[5] NULL; // 定义一个指向 拥有5个整型数据的数组…

Linux---sudo命令

文章目录 目录 文章目录 一.sudo命令简介 二.sudo 命令的特点 三.sudo 相关文件 四.sudo 命令授权配置 一.sudo命令简介 sudo 命令全称“SuperUser Do”&#xff0c;是Linux系统中的一个命令能够使普通用户以超级用户身份去执行某些命令。 二.sudo 命令的特点 sudo能够授权…

翻译《The Old New Thing》- How do I obtain the computer manufacturer’s name?

How do I obtain the computer manufacturers name? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20081218-00/?p19783 Raymond Chen 2008年08月08日 如何获取计算机制造商的名字&#xff1f; 一位客户想要一种方法来确定计算机制造商的…

vuInhub靶场实战系列--prime:2

免责声明 本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关。 目录 免责声明前言一、环境配置1.1 靶场信息1.2 靶场配置 二、信息收集2.1 主机发现2.1.1 netdiscover2.1.2 nmap主机扫描2.1.3 arp-scan主机扫描 2.2 端口扫描…

Flutter中同步与异步

一&#xff0c;同步/异步的理解 1&#xff0c;await&#xff1a;同步机制 同步操作会阻止其他操作执行&#xff0c;直到完成为止。同步就好比打电话一样&#xff0c;打电话时都是一个人在说另一个人听&#xff0c;一个人在说的时候另一个人等待&#xff0c;等另一个人说完后再…

OCP-042之:Oracle结构体系

1. Oracle结构体系 1.1 概述 1.1.1 版本 版本后缀所代表的含义 i:代表基于Internet架构的数据库,如9i g:代表基于grid(网格)的数据库,如11g grid的目的:降低成本,提高服务质量,简化管理 Storage Grid:ASM(automatic storage management),继承了LVM技术,Oracl…

Git【版本控制和Git的安装介绍】

01 【版本控制和Git的安装介绍】 工程设计领域中&#xff0c;使用“版本控制”管理工程蓝图的设计过程。在 IT 开发中也可以使用版本控制思想管理代码的版本迭代。 1.目的 协同修改&#xff1a;支持在服务器对同一个文件多人协同地修改&#xff1b; 数据备份&#xff1a;同时…

java中的异常-异常处理(try、catch、finally、throw、throws)+自定义异常

一、概述 1、java程序员在编写程序时提前编写好对异常的处理程序&#xff0c;在程序发生异常时就可以执行预先设定好的处理程序&#xff0c;处理程序执行完之后&#xff0c;可以继续向后执行后面的程序 2、异常处理程序是在程序执行出现异常时才执行的 二、5个关键字 1、tr…

11 gpio 与 pinctrl 子系统

1、GPIO 硬件结构 GPIO 是通用输入/输出端口的简称。GPIO 的引脚与外部硬件设备连接,可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。 八种工作模式 GPIO_Mode_AIN 模拟输入 GPIO_Mode_IN_FLOATING 浮空输入 GPIO_Mode_IPD 下拉输入 GPIO_Mode_IPU 上拉输入GP…

Hadoop笔记

1.hadoop环境搭建&#xff0c;linux命令&#xff08;vi);2.分布式的基本概念&#xff0c;cap理论&#xff08;遵循此原则开发分布式数据库&#xff09;&#xff0c;hdfs,mapreduce&#xff1b;3.3.1&#xff1b;3.2重点&#xff1b;4.map&#xff0c;reduce过程&#xff0c;优缺…

DBeaver无法连接Clickhouse,连接失败

DBeaver默认下载的是0.2.6版本的驱动&#xff0c;但是一直连接失败&#xff1a; 报错提示 解决办法 点击上图中的Open Driver Configuration点击库 - 重置为默认状态在弹出的窗口中修改驱动版本号为0.2.4或者其他版本&#xff08;我没有试用过其他版本&#xff09;&#xff0…

c++【入门】求圆环的面积

限制 时间限制 : 1 秒 内存限制 : 128 MB 题目 如下图所示的圆环铁片&#xff0c;中间是空心的&#xff0c;已知圆环外圆的半径是r1厘米&#xff08;如&#xff1a;10cm&#xff09;&#xff0c;内圆半径是r2厘米&#xff08;如&#xff1a;6cm&#xff09;&#xff0c;请编…

stm32最小系统焊接调试总结

stm32最小系统打板后,接下来开始焊接元器件,焊接元器件可以参考立创EDA焊接辅助工具。 图1 焊接辅助助手 焊接准备工具有,焊台,放大镜,元器件,镊子,焊锡膏,锡丝及万用表等。调节焊台温度到350-400摄氏度。焊接顺序是先焊接USB typec接口,5V电源,ldo,ch340,stm32芯片…

标准发布实施 | 《村镇污水处理一体化集成装备技术规范》

根据《中华人民共和国标准化法》以及国家标准化管理委员会、民政部联合制定的《团体标准管理规定》&#xff0c;依据全国团体标准信息平台和《中华环保联合会团体标准管理办法&#xff08;试行&#xff09;》&#xff0c;全国团体标准《村镇污水处理一体化集成装备技术指南》&a…

32.768k晶振FC-135R在智能手表手环中的作用

随着智能设备的普及&#xff0c;智能手表和手环已经成为人们日常生活中不可或缺的科技产品。晶振在智能手表手环中的作用是通过传感器给智能手环连接提供信号频率&#xff0c;是很重要的核心部位&#xff0c;这些设备的核心在于其精准的时钟管理和低功耗特性&#xff0c;32.768…

Polar Web【中等】xxe

Polar Web【中等】xxe Contents Polar Web【中等】xxe思路&探索EXP运行&总结 思路&探索 如题目所示&#xff0c;此题考查XXE漏洞&#xff0c;具体细节需要逐步深挖 打开站点&#xff0c;提示了flag所在的文件&#xff0c;点击按钮&#xff0c;可见php的配置信息&am…