【数据结构与算法】十大经典排序算法-快速排序

🌟个人博客:www.hellocode.top
🏰Java知识导航:Java-Navigate
🔥CSDN:HelloCode.
🌞知乎:HelloCode
🌴掘金:HelloCode
⚡如有问题,欢迎指正,一起学习~~


快速排序(Quick Sort)是一种高效的排序算法,是对冒泡排序的优化。它采用分治法(Divide and Conquer)的思想,将待排序序列不断分割成较小的子序列,然后对每个子序列进行排序,最后合并得到有序的序列。快速排序在大多数情况下具有优异的性能,是许多常见排序算法中最快的之一。

基本思想

快速排序动画演示

这里的动画用大佬五分钟学算法的图,很清晰

  1. 选择一个基准元素(pivot)作为参考点。
  2. 将所有比基准元素小的元素移到基准元素的左边,将所有比基准元素大的元素移到基准元素的右边。此过程称为分区(partitioning)。
  3. 对基准元素左右两边的子序列递归地进行相同的快速排序,直到子序列的大小为1或0,表示子序列已经有序。

如上图所示,快速排序的基本思想就是选取一个基准数,将基准数小的都放在左边,大的都放在右边,也就是每次循环都会确定出基准数应该在的正确位置。

代码实现

对应在代码层面,需要使用到递归法来实现,对于快速排序来说,递归相对还是很容易想到的

/*** @author HelloCode* @blog https://www.hellocode.top* @date 2023年08月08日 21:14*/
public class QuickSort {public static void quickSort(int[] arr) {// 特殊情况处理if (arr == null || arr.length == 0 || arr.length == 1) {return;}// 递归入口sort(arr, 0, arr.length - 1);}private static void sort(int[] arr, int left, int right) {// 递归出口if (left > right) {return;}// 初始化双指针int i = left, j = right;// 选取基准数int base = arr[left];while (i != j) {// (注意!!!!)从右边开始// 找比基准数小的while (i < j && arr[j] >= base) {j--;}// 从左边找比基准数大的while (i < j && arr[i] <= base) {i++;}// 交换i jif (i < j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}// 基准数归位(此时i == j)arr[left] = arr[i];arr[i] = base;// 开始左右两边分别快排sort(arr, left, i - 1);sort(arr, i + 1, right);}
}

这里先移动j还是先移动i主要是需要看基准数选取的位置,如果选最左边的数,就需要先移动j(确保i == j 时对应的值是小于基准数的,再把基准数和该数交换,符合排序规则)
如果选取的基准数是最右边,则先移动i指针(确保 i == j 时对应的值是大于基准数的)

测试:

/*** @author HelloCode* @blog https://www.hellocode.top* @date 2023年08月08日 21:14*/
public class Test {public static void main(String[] args) {int[] arr = {21, 13, 4, 10, 7, 65, 32, 15, 32, 19, 33, 65, 89, 72, 12};System.out.println("排序前:" + Arrays.toString(arr));QuickSort.quickSort(arr);System.out.println("排序后:" + Arrays.toString(arr));}
}

image-20230808213942941

优化

快排的优化主要需要关注基准数的选取,如果待排序数组整体偏降序,此时还选最左侧的为基准数的话,效率就相对慢一些,所以选取一个好的基准数可以让快排的效率更加稳定~

主要的方法有以下几种:

  1. 随机选择基准元素:选择随机的基准元素可以降低最坏情况的概率,进而提高算法性能。
  2. 三数取中法:在选取基准元素时,不是简单地选取第一个或最后一个元素,而是选择中间元素、第一个元素和最后一个元素中的中位数作为基准元素,也可以降低最坏情况的概率。

这里基准数的选取可以很巧妙,还有很多种其他方法,都可以降低最坏情况的发生,本文以三数取中法为例:

/*** @author HelloCode* @blog https://www.hellocode.top* @date 2023年08月08日 21:14*/
public class QuickSort {public static void quickSort(int[] arr) {// 特殊情况处理if (arr == null || arr.length == 0 || arr.length == 1) {return;}// 递归入口sort(arr, 0, arr.length - 1);}private static void sort(int[] arr, int left, int right) {// 递归出口if (left > right) {return;}// 初始化双指针int i = left, j = right;// 选取基准数getBase(arr, left, right);int base = arr[left];while (i != j) {// (注意!!!!)从右边开始// 找比基准数小的while (i < j && arr[j] >= base) {j--;}// 从左边找比基准数大的while (i < j && arr[i] <= base) {i++;}// 交换i jif (i < j) {swap(arr, i, j);}}// 基准数归位(此时i == j)arr[left] = arr[i];arr[i] = base;// 开始左右两边分别快排sort(arr, left, i - 1);sort(arr, i + 1, right);}// 取三点中间值(最终会移动到left位置,这样可以不改变原有代码)private static void getBase(int[] arr, int left, int right) {// 这里可以防止溢出且使用 >> 效率相对能高一些// 等价于 (left + right) / 2int mid = left + ((right - left) >> 1);// 确保第一个元素最小if (arr[left] > arr[right]) {swap(arr, left, right);}// 确保最后一个元素最大if (arr[mid] > arr[right]) {swap(arr, mid, right);}// 确定mid就是中间值,交换到最左边if (arr[left] < arr[mid]) {swap(arr, left, mid);}System.out.println("基准数为:" + arr[left]);}// 交换数组两下标元素位置private static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
}

测试:

/*** @author HelloCode* @blog https://www.hellocode.top* @date 2023年08月07日 21:02*/
public class Test {public static void main(String[] args) {int[] arr = {21, 13, 4, 10, 7, 65, 32, 15, 32, 19};System.out.println("排序前:" + Arrays.toString(arr));BubbleSort.bubbleSortOptimized1(arr);System.out.println("排序后:" + Arrays.toString(arr));}
}
排序前:[21, 13, 4, 10, 7, 65, 32, 15, 32, 19, 33, 65, 89, 72, 12]
基准数为:15
基准数为:7
基准数为:4
基准数为:12
基准数为:10
基准数为:13
基准数为:32
基准数为:21
基准数为:19
基准数为:32
基准数为:65
基准数为:33
基准数为:65
基准数为:72
基准数为:89
排序后:[4, 7, 10, 12, 13, 15, 19, 21, 32, 32, 33, 65, 65, 72, 89]

总结

优点

  1. 高效性:快速排序是一种高效的排序算法,在大多数实际情况下,它的性能通常比其他常见排序算法(如冒泡排序、插入排序)更好。
  2. 原地排序:快速排序是原地排序算法,不需要额外的辅助空间,只需在原始数组上进行交换操作。

缺点

  1. 最坏情况下的性能:当待排序序列已经基本有序或完全逆序时,快速排序的时间复杂度退化为 O(n^2),导致性能下降。这是因为基准元素的选择可能导致分区不平衡,使得分区操作不再能有效地减少问题规模。
  2. 不稳定性:快速排序是一种不稳定的排序算法,意味着相等元素的相对顺序在排序后可能发生变化。这在某些情况下可能导致问题,特别是对于复杂对象的排序,需要额外的处理来保持稳定性。

复杂度

  • 时间复杂度:快速排序的平均时间复杂度为O(n log n),最坏情况下为O(n^2)。
  • 空间复杂度:快速排序是原地排序算法,空间复杂度为O(log n)。

适用于处理大规模数据集的排序,尤其在平均情况下,快速排序的性能较优。但在处理已经有序或近乎有序的数据集时,快速排序的性能可能会下降,这时候其他稳定的排序算法可能更合适。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ffmpeg+intel核显实现硬解码

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、前言二、检查方法1.图形法2.nvidia-smi3.intel-gpu-tools 三、安装使用1.libva-dev2.libva-utils3.编译安装4.测试1.vainfo2.ffmpeg测试解码 总结 前言 之…

腾讯云轻量应用服务器镜像应用模板清单大全

腾讯云轻量应用服务器支持多种应用模板镜像&#xff0c;Windows和Linux镜像模板都有&#xff0c;如&#xff1a;宝塔Linux面板腾讯云专享版、WordPress、WooCommerce、LAMP、Node.js、Docker CE、K3s、宝塔Windows面板和ASP.NET等应用模板镜像&#xff0c;腾讯云服务器网分享腾…

PHP 门户信息网站系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 门户信息网站系统 是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 下载地址https://download.csdn.net/download/qq_41221322/88179035https://downlo…

剑指 Offer 40. 最小的k个数

题目描述 输入整数数组 arr &#xff0c;找出其中最小的 k 个数。例如&#xff0c;输入4、5、1、6、2、7、3、8这8个数字&#xff0c;则最小的4个数字是1、2、3、4。 示例 思路 方法1 采用未改进的快速排序 class Solution {public int[] getLeastNumbers(int[] arr, int k…

创建型模式-原型模式

文章目录 一、原型模式1. 概述2. 结构3. 实现4. 案例1.5 使用场景1.6 扩展&#xff08;深克隆&#xff09; 一、原型模式 1. 概述 用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 2. 结构 原型模式包含如下角色&#xff1a; …

SQL常见命令语句

1.连接数据库 mysql (-h IP) -u root -p 密码2.查看数据库 show databases3.使用数据库 use db_name4.查看表 show tables [from db_name]5.查看表结构 desc tb_name6.创建、删除、选择数据库 create database db_namedrop database db_nameuse db_name7.数据类型 参考链…

【jackson】自定义字段注解完成序列化逻辑

目录 背景本文开发环境介绍新建一个注解新建一个JavaBean新建一个JsonSerializer新建一个AnnotationIntrospector单元测试总结 背景 Spring默认的JSON序列化工具使用的是jackson&#xff0c;GitHub项目地址: https://github.com/FasterXML/jackson 我们在处理前后端接口交互的…

学习笔记|LED点亮原理|三极管在数字电路中的应用|Keil中的Tab设置|C51中对准双向口|STC32G单片机视频开发教程(冲哥)|第四集-上:点亮LED

文章目录 1.LED点亮原理STC32G12K128LQFP64QFN64管脚图&#xff1a;Tips&#xff1a;USB-ISP下载程GPIO (general purpose intput output&#xff09;Tips&#xff1a;三极管在数字电路中的应用 2 新建工程Tips:Tab设置TIPS: sbit c语言中特殊功能寄存器的位变量11.2 配置IO口注…

基于kubeasz部署高可用k8s集群

在部署高可用k8s之前&#xff0c;我们先来说一说单master架构和多master架构&#xff0c;以及多master架构中各组件工作逻辑 k8s单master架构 提示&#xff1a;这种单master节点的架构&#xff0c;通常只用于测试环境&#xff0c;生产环境绝对不允许&#xff1b;这是因为k8s集群…

5.0SMDJ24CA 瞬态抑制TVS二极管 可过4kV 2Ω测试

瞬态概述 浪涌描述的是存在于电源或信号线上uS级以上的脉冲。通常浪涌产生于雷击或开关瞬变能量。雷击能量可能是由于直击雷或感应雷作用于系统所产生的瞬变能量&#xff0c;开关瞬变能量通常由于配电系统的电源切换&#xff0c;或是负载的变化导致。 雷击浪涌测试目的 GB/T …

医疗保健中的 NLP:实体链接

一、说明 HEalthcare和生命科学行业产生大量数据&#xff0c;这些数据是由合规性和监管要求&#xff0c;记录保存&#xff0c;研究论文等驱动的。但随着数据量的增加&#xff0c;搜索用于研究目的的必要文件和文章以及数据结构成为一个更加复杂和耗时的过程。例如&#xff0c;如…

【学习FreeRTOS】第6章——FreeRTOS中断管理

【本篇文章的也可参考STM32中断文章http://t.csdn.cn/foF9I&#xff0c;结合着学习效果更好】 1.什么是中断 中断&#xff1a;让CPU打断正常运行的程序&#xff0c;转而去处理紧急的事件&#xff08;程序&#xff09;&#xff0c;就叫中断中断执行机制&#xff0c;可简单概括…