排序算法之——快速排序

快速排序

  • 1.基本思想
  • 2.图示详解——以升序排列为例
  • 3.对基本思想和图示的补充说明
  • 4.代码实现
  • 5.空间、时间复杂度
    • 5.1最好情况
    • 5.2最坏情况
  • 6.区间按照基准值划分的方法
    • 6.1 Hoare法
    • 6.2 挖坑法
  • 7.优化措施
    • 7.1三数取中法
      • 7.1.1三数取中法——核心代码
      • 7.1.2优化效果
      • 7.1.3补充说明
    • 7.2 递归到小的子区间时,使用插入排序
  • 8.排序算法的非递归实现
    • 8.1核心思路
    • 8.2详细图解
    • 8.3代码实现
      • 8.3.1伪码
      • 8.3.2源码
      • 8.3.3测试结果

1.基本思想

快速排序是Hoare于1962年提出的一种二叉树结构交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

2.图示详解——以升序排列为例

在这里插入图片描述

3.对基本思想和图示的补充说明

①1.基本思想里的任取待排序元素序列中的某元素作为基准值——这个基准值的选取是任意的,可以是给定数据中的任何一个数据。只不过为了演示方便,我们一般选举数据的第一个或最后一个值作为基准值
②图示详解里的排序过程,我们会发现与二叉树前序遍历规则非常像。这也就是为什么说快速排序二叉树结构交换排序方法。

4.代码实现

/*** 快速排序* @param array*/public static void quickSort(int[] array){quick(array,0,array.length -1);  //quickSort()调用quick()方法是为了使参数统一为数组array[]}private static void quick(int[] array,int start,int end){if(start >= end){return;  //递归结束的条件}int pivot = partitionHoare(array,start,end);//划分原数组并找出中心点pivotquick(array,start,pivot - 1);quick(array,pivot+1,end);}/*** Hoare法* @param array* @param left* @param right* @return*/private static int partitionHoare(int[] array,int left,int right){int tmp = array[left];int i = left;//i记录待排序数据的最左侧的下标值while(left < right){while(left < right && array[right] >= tmp){//right往前走直到遇到小于tmp的值right--;}while(left < right && array[left] <= tmp){//left往后走直到遇到大于tmp的值left++;}swap(array,left,right);//left、right停下时交换其处的数据值}//此时,left和right相遇,left的值就是我们要找的中心点的下标swap(array,i,left);//交换基准值和pivot下标处的值return left;}

运行结果:

在这里插入图片描述
在这里插入图片描述
注意事项
在这里插入图片描述
上述代码,外层循环的控制条件为:left < right,两个内层循环也需要加上left < right。举个例子:对于一组数据1,2,3,4,5。

在这里插入图片描述
如果内层循环不加上left < right,则right可能会走到负数坐标位置,导致数组越界。

5.空间、时间复杂度

5.1最好情况

参考图示详解和二叉树的相关知识,如果给定一组容量为n的数据,如果每次寻找中心点 pivot,pivot的位置都在待排序的那组数据的正中间,则可以创建一棵完全二叉树,此时树的高度是log2(n+1)(向上取整),因此空间复杂度为O(log2(n))。对每一层,left和right总的遍历次数是n,因此时间总的复杂度为O(n*log2(n))
在这里插入图片描述

5.2最坏情况

如果给定的一组容量为n的数据,本身已经升序排列了。则最后形成的二叉树是一个只有右子树没有左子树的二叉树,共有n层,因此空间复杂度为O(n)。第1层,left和right共遍历n次,第2层eft和right共遍历n-1次,第3层eft和right共遍历n-2次…最后left和right总共的遍历次数为n + (n-1) + (n-2) + … + 1 = n (n+1) / 2。因此总的时间复杂度为O(n^2)
在这里插入图片描述

6.区间按照基准值划分的方法

区间按照基准值划分为左右两半部分的常见方式有多种。常见的方式有:

6.1 Hoare法

Hoare法即前文所演示的方法,下面介绍挖法。

6.2 挖坑法

挖坑法图示:
在这里插入图片描述
核心代码:

/*** 挖坑法* @param array* @param left* @param right* @return*/private static int partitionDigPit(int[] array,int left,int right){int tmp = array[left];while(left < right){while(left < right && array[right] >= tmp){ //left往后走直到遇到大于tmp的值right--;}array[left] = array[right];while(left < right && array[left] <= tmp){ //right往前走直到遇到小于tmp的值left++;}array[right] = array[left];}//此时,left和right相遇,将tmp的值填回left处,left的值就是我们要找的中心点的下标array[left] = tmp;return left;}

7.优化措施

7.1三数取中法

由前面的演示我们知道,理想情况下,如果每次划分数据时,都能均匀地分成两组,这样最终递归而成地就是一个完全二叉树,快速排序地用时将会减少。为此,我们采用三数取中法,以寻找每次排序时的基准值

举例如下:给定一组数据3,4,9,12,14,18,27 。如果采用快速排序进行升序排列,由前文知道,此时递归过程相当于创建了一个层高为7的单分支(只有右子树)二叉树。这是由于每次排序时,都以当前待排序数据的最左侧元素作为基准值。现采用三数取中法,调整每次排序时选取的基准值。图示如下:

在这里插入图片描述

7.1.1三数取中法——核心代码

private static void quick(int[] array,int start,int end){if(start >= end){return;  //递归结束的条件}//1.三数取中int index = middleNumberIndex(array,start,end);//找到中间值的下标swap(array,start,index);//交换中间值和第一个元素的值int pivot = partitionHoare(array,start,end);//划分原数组并找出中心点pivot//int pivot = partitionDigPit(array,start,end);//划分原数组并找出中心点pivotquick(array,start,pivot - 1);quick(array,pivot+1,end);}
/***  寻找给定数组的第一个元素值、最后一个元素值、中间位置的元素中的中间值,并返回其坐标* @param array* @param left* @param right* @return*/private static int middleNumberIndex(int[] array,int left,int right){int mid = left + (right - left) / 2;if(array[left] < array[right]){if(array[mid] < array[left]){return left;}else if(array[mid] > array[right]){return right;}else{return mid;}}else{if(array[mid] < array[right]){return right;}else if(array[mid] > array[left]){return left;}else{return mid;}}}

7.1.2优化效果

对一组容量为200000的数据分别初始化为升序、降序、乱序,采用三数取中法优化前后的效果图如下,测试结果的单位是毫秒(每一组测试笔者都测试了多次,这里取的是一个大概的均值):
在这里插入图片描述
可以看到,在本案例中,三数取中法对升序数组的排列优化效果最明显,这与我们之前的分析吻合。如果快速排序每次选取的基准值不是待排序数据的第1个,而是最后一个呢?感兴趣的读者可以自己下去研究以下。

7.1.3补充说明

三数取中法可以使我们每次对数据分割时,分割后的两组数据趋于均衡,而不是绝对均衡,绝对均衡的情况只在理想情况下才出现。但是这不妨碍三数取中法成为一个不错的优化策略,毕竟相对于不优化,三数取中法在某些情况下(对于升序、乱序数据的处理)还是具有明显的降时间效果的。

7.2 递归到小的子区间时,使用插入排序

分析:当我们递归到很小的子区间时,如果再进行递归排序的话,这个时间开销会很大。因为递归的过程包括递归进去和回退两方面,效率是比较低的,想象一下,一棵完全二叉树的最后一层节点个数占了整个二叉树节点个数的将近一般。所以此时采用的策略是:在每个小子区间上进行插入排序,这样比一直递归下去要节省时间。

8.排序算法的非递归实现

8.1核心思路

利用栈模拟递归过程,从而实现排序算法。

8.2详细图解

在这里插入图片描述
通过图示我们发现,整个过程是将整个数组从后往前逐渐变得有序的。

8.3代码实现

8.3.1伪码

在这里插入图片描述

8.3.2源码

  public static void quickSortNotRecursion(int[] array){Stack<Integer> stack = new Stack<>();int left = 0;int right = array.length - 1;int pivot = partitionHoare(array,left,right);if(pivot - 1 > left){//中心点两侧有>=2个数据stack.push(left);stack.push(pivot - 1);}if(pivot + 1 < right){//中心点两侧有>=2个数据stack.push(pivot + 1);stack.push(right);}while(stack.isEmpty() == false){right = stack.pop();left = stack.pop();pivot = partitionHoare(array,left,right);if(pivot - 1 > left){//中心点两侧有>=2个数据stack.push(left);stack.push(pivot - 1);}if(pivot + 1 < right){//中心点两侧有>=2个数据stack.push(pivot + 1);stack.push(right);}}}

8.3.3测试结果

在这里插入图片描述

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

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

相关文章

docker 容器内服务随容器自动启动

docker 容器内服务随容器自动启动 背景准备工作方案一&#xff0c;直接修改.bashrc文件&#xff08;简单粗暴&#xff09;方案二&#xff0c;编写启动脚本加入.bashrc文件&#xff08;文明一点&#xff09;制作nginx服务自启动镜像测试新镜像&#xff0c;nginx服务随容器自动启…

回显服务器的制作方法

文章目录 客户端和服务器TCP和UDP的特点UDP socket api的使用DatagramSocketDatagramPacketInetSocketAddress API 做一个简单的回显服务器UDP版本的回显服务器TCP版本的回显服务器 客户端和服务器 在网络中&#xff0c;主动发起通信的一方是客户端&#xff0c;被动接受的这一方…

Rman全备和增量备份说明

RMAN备份分为全备和增量备份&#xff0c;全备不能成为增量备份策略的一部分&#xff0c;它也不能作为后续增量备份的基础。 RMAN增量备份分为0、1、2三级&#xff0c;其中0级备份是增量备份的基础&#xff0c;备份内容也跟全备份一样&#xff0c;要使用增量备份&#xff0c;必…

华为交换机如何配置Web网管登录?直接用网页管理交换机

Web网管是一种对交换机的管理方式&#xff0c;它利用交换机内置的Web服务器&#xff0c;为用户提供图形化的操作界面。用户可以从终端通过HTTPS登录到Web网管&#xff0c;对交换机进行管理和维护&#xff0c;同时也非常方便。 一、配置思路&#xff1a; 1、配置管理IP地址&am…

mysql 自定义函数create function

方便后续查询&#xff0c;做以下记录&#xff1b; 自定义函数是一种与存储过程十分相似的过程式数据库对象&#xff0c; 它与存储过程一样&#xff0c;都是由 SQL 语句和过程式语句组成的代码片段&#xff0c;并且可以被应用程序和其他 SQL 语句调用。 自定义函数与存储过程之间…

提供英语励志名言的软件有哪些?这些软件不可错过

提供英语励志名言的软件有哪些&#xff1f;在追求个人成长和激励的道路上&#xff0c;英语励志名言常常为我们提供前进的动力。这些言简意赅、充满智慧的话语&#xff0c;不仅能在我们迷茫时指引方向&#xff0c;还能在挫折中给予我们勇气和力量。如今&#xff0c;随着科技的发…

stm32和嵌入式linux可以同步学习吗?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「stm3的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;如果需要使用STM32&#xff0c;建…

http://127.0.0.1:9222/json打不开Chrome环境变量问题

解决方案&#xff1a; 系统环境变量Path设置错误&#xff0c; 1、先看下端口是否占用&#xff1a;netstat -ano|findstr “9222” &#xff0c; 如下127.0.0.1:9222端口显示LISTENING是正常的 如果是SYN_SENT可能不太正常&#xff0c;这个时候&#xff0c; taskkill /PID 端…

【前端素材】推荐优质后台管理系统APP Zina平台模板(附源码)

一、需求分析 当我们从多个层次来详细分析后台管理系统时&#xff0c;可以将其功能和定义进一步细分&#xff0c;以便更好地理解其在不同方面的作用和实际运作。 1. 功能层次 a. 用户管理功能&#xff1a; 用户注册和登录&#xff1a;管理用户账户的注册和登录过程。权限管…

如何使用Docker部署开源Leanote蚂蚁笔记并发布个人博客至公网

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 1. 安装Docker2. Docker本地部署Leanote蚂蚁笔记3. 安装…

notepad++运行python闪一下就没啦

问题&#xff1a;Notepad直接快捷键运行Python代码,出现闪一下就没了 解决措施&#xff1a; ①点击菜单运行(Run) --> 运行(Run)弹出的对话框 ②把 cmd /k python "$(FULL_CURRENT_PATH)" & ECHO. & PAUSE & EXIT 粘贴进入这个对话框内 ③点击保存&a…

由面试题“Redis是否为单线程”引发的思考

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

边坡位移监测设备:守护工程安全的前沿科技

随着现代工程建设的飞速发展&#xff0c;边坡位移监测作为预防山体滑坡、泥石流等自然灾害的重要手段&#xff0c;日益受到人们的关注。边坡位移监测设备作为这一领域的关键技术&#xff0c;以其高精度、实时监测的特点&#xff0c;成为守护工程安全的重要武器。 一、边坡位移…

信钰证券|印花税下降对股市的影响?印花税下降利好哪些板块?

投资者在买卖股票时&#xff0c;需求交纳一定的佣金费用、印花税和过户费用&#xff0c;其间印花税和过户费用&#xff0c;随着方针的变动&#xff0c;会进行相应的调整&#xff0c;那么&#xff0c;印花税下降对股市的影响&#xff1f;印花税下降利好哪些板块&#xff1f; 印花…

(科目三)信息技术基础

1.信息与信息技术概述 1.1 信息的定义和表示 一、信息的定义&#xff1a; 信息就是通过语言、文字、图形/图像、声音、视频等传播的内容。 信息≠消息&#xff0c;信息就是消息的内核&#xff0c;消息是信息的外壳。 信息不是某种信号&#xff0c;也不等同于知识。 数据&…

算法沉淀——穷举、暴搜、深搜、回溯、剪枝综合练习三(leetcode真题剖析)

算法沉淀——穷举、暴搜、深搜、回溯、剪枝综合练习三 01.字母大小写全排列02.优美的排列03.N 皇后04.有效的数独 01.字母大小写全排列 题目链接&#xff1a;https://leetcode.cn/problems/letter-case-permutation/ 给定一个字符串 s &#xff0c;通过将字符串 s 中的每个字…

安装Windows Server 2025 搭建免费云桌面系统

介绍 Windows Server 2025 为 Hyper-V 带来了多项增强功能和新的存储特性&#xff0c;主要用于优化虚拟机的运行体验。这些新特性涵盖 GPU 虚拟化、新的 ReFS 去重功能&#xff0c;以及在非 AD 域的集群上进行虚拟机实时迁移。 云桌面方案的用户最关心的GPU-P的技术也将在Win…

VMware虚拟机文件夹共享失效

问题现象 今天开启虚拟机的时候就看到这个&#xff0c;感觉又要有不好的事情发生了。 果不其然&#xff0c;开机之后弹出这个&#xff0c;我当时还没意识到这个dll文件会对我的正常使用产生什么样的影响。 然后就发现文件根本拷贝不进去虚拟机里面&#xff0c;连虚拟机里面的共…

缓存篇—缓存雪崩、缓存击穿、缓存穿透

缓存异常会面临的三个问题&#xff1a;缓存雪崩、击穿和穿透。 其中&#xff0c;缓存雪崩和缓存击穿主要原因是数据不在缓存中&#xff0c;而导致大量请求访问了数据库&#xff0c;数据库压力骤增&#xff0c;容易引发一系列连锁反应&#xff0c;导致系统奔溃。不过&#xff0…

petalinux_zynq7 驱动DAC以及ADC模块之三:实现C语言API并编译出库被python调用

前文&#xff1a; petalinux_zynq7 C语言驱动DAC以及ADC模块之一&#xff1a;建立IPhttps://blog.csdn.net/qq_27158179/article/details/136234296petalinux_zynq7 C语言驱动DAC以及ADC模块之二&#xff1a;petalinuxhttps://blog.csdn.net/qq_27158179/article/details/1362…