JAVA-快速排序
目录
一、快速排序基本思想
二、快速排序的实现
1.Hoare法找基准值
2.挖坑法
3.前后指针法(了解)
三、快速排序的优化
1.三数取中法
2.递归到小的子区间时,可以考虑使用插入排序
四、非递归的写法
五、时间空间复杂度
一、快速排序基本思想
我们此次实现拿数组的第一个元素做为基准值![]()
right找到比tmp小的,left再找到比tmp大的就交换。如果交汇了就放入第一个元素,再把tmp放进来。 right必须先找left后找
把交汇处的下标给par,再分别从par两边重复之前的操作。而且这不就是二叉树吗。那么就适合用递归来处理了
二、快速排序的实现
public static void quickSort(int[] array) {quick(array,0,array.length-1);}private static void quick(int[] array,int start,int end) {//当start >= end了证明只有一个元素,或者没有左右树了也就不需要排序了if(start >= end) {return;}//按照基准值对array数组的 [start,end]区间中的元素进行划分//并返回当前基准值下标int par = partitionHoare(array,start,end);//遍历左边quick(array,start,par-1);//遍历右边quick(array,par+1,end);}
1.Hoare法找基准值
从逻辑上已经构造好了,就差具体的操作了:
/*** Hoare法* @param array* @param left* @param right* @return*/private static int partitionHoare(int[] array, int left,int right) {//用来保存基准值下标int i = left;//记录基准值的值int tmp = array[left];//没交汇就继续循环while (left < right) {//left < right 必须写前面,防止6 7 8 9这种情况//找到最右边小于基准值的值while (left < right && array[right] >= tmp){right--;}//找到左边大于基准值的值while (left < right && array[left] <= tmp) {left++;}//交换swap(array,left,right);}//此时 left 和 right 交汇swap(array,i,left);//返回新的基准值下标return left;}//交换函数private static void swap(int[] array, int i, int j) {int tmp = array[i];array[i] = array[j];array[j] = tmp;}
测试代码:
public static void main(String[] args) {int[] array = {10,9,7,2,3,8,1};Sort.bubbleSort(array);System.out.println(Arrays.toString(array));}
出了刚才的Hoare法可以找基准值下面还有两种方法
2.挖坑法
先把基准值记录一下,再由right找到小于基准值的,然后left找到大于基准值的。两边来回填补。
最后tmp放入交汇处
细心的就会发现,这和Hoare法的数据顺序是不一样的。但也同样达到了效果
画图的时候里面有一些空,其实是保留了原来数据的,但是为了更好的理解就没有保留。但是在代码上原有的数据一定会被覆盖。
代码:
/*** 挖坑法* @param array* @param left* @param right* @return*/private static int partitionK(int[] array, int left,int right) {//记录第一个坑,做为基准值int tmp = array[left];while (left < right) {//找到最左边比基准值小的while (left < right && array[right] >= tmp) {right--;}//左边小的数据先放入,已经挖好了坑tmparray[left] = array[right];//找到最右边大于基准值的while (left < right && array[left] <= tmp) {left++;}//放入右边的新坑array[right] = array[left];}//left 和 right 交汇,填空array[left] = tmp;return left;}
这是最重要的一种方法,着重掌握
3.前后指针法(了解)
做选择题的时候可能会有。做题顺序: 挖坑法 > Hoare法 > 前后指针法
/*** 前后指针法 (做为了解)* @param array* @param left* @param right* @return*/private static int partitionPre(int[] array, int left, int right) {int prev = left ;int cur = left+1;while (cur <= right) {if(array[cur] < array[left] && array[++prev] != array[cur]) {swap(array,cur,prev);}cur++;}swap(array,prev,left);return prev;}
快速排序如果不做优化,数据量大了以后他是很有可能会栈溢出的。
但是计算做了优化也有可能会栈溢出,虽然快速排序是最快的,但耗费内存大也是他的缺点
三、快速排序的优化
1.三数取中法
快排在能取到中间值时,最快。
如果数组是一个有序的,那么就会开辟很多没必要的空间。浪费时间空间
那么三树取中就是:
用left 和 right 与 mid(数组中间下标的值) ,里面选居中的一个。做为基准值,并将他和left换一下
此时3做为基准值
那么最后基准值就在中间位置
写一个函数找到三个数之间中间的那个数的下标:
//返回的是中间值小标private static int midTreeNum(int[] array,int left,int right) {int mid = (left + right) / 2;if(array[left] < array[right]) {if(array[mid] < array[left]) {return left;}else if(array[right] < array[mid]) {return right;}else {return mid;}}else {if(array[mid] < array[right]) {return right;}else if(array[left] < array[mid]) {return left;}else {return mid;}}}
边看图边看代码,假设array[left] < array[right] 假设array[left] >= array[right]
public static void quickSort(int[] array) {quick(array,0,array.length-1);}private static void quick(int[] array,int start,int end) {if(start >= end) {return;}//三数取中法int index = midTreeNum(array,start,end);swap(array,index,start);int par = partitionK(array,start,end);quick(array,start,par-1);quick(array,par+1,end);}
结果:
2.递归到小的子区间时,可以考虑使用插入排序
我们知道在趋于有序的时候插入排序最快,可以达到O(n)
public static void insertSortRange(int[] array,int left ,int right) {for (int i = left+1; i <= right; i++) {int tmp = array[i];int j = i-1;for (; j >= left; j--) {
// if(array[j] > tmp) { 不稳定的写法if(array[j] > tmp) {array[j+1] = array[j];}else {//防止第一次array[j]>tmp,从而j--到-1,执行不到这条语句
// array[j+1] = tmp;break;}}array[j+1] = tmp;}
}
public static void quickSort(int[] array) {quick(array,0,array.length-1);}private static void quick(int[] array,int start,int end) {if(start >= end) {return;}//当分出来的,数组越小。递归的次数就越多了,但是趋于有序了就可以用插入排序if(end - start + 1 <= 10) {insertSortRange(array,start,end);return;}//三数取中法int index = midTreeNum(array,start,end);swap(array,index,start);int par = partitionK(array,start,end);quick(array,start,par-1);quick(array,par+1,end);}
四、非递归的写法
public static void quickSortNot(int[] array) {Stack<Integer> stack = new Stack<>();int left = 0;int right = array.length-1;int par = partitionK(array,left,right);if(par > left+1) {stack.push(left);stack.push(par-1);}if(par < right-1) {stack.push(par+1);stack.push(right);}while (!stack.isEmpty()) {right = stack.pop();left = stack.pop();par = partitionK(array,left,right);//保证左边至少有两个元素if(par > left+1) {stack.push(left);stack.push(par-1);}//保证右边至少有两个元素if(par < right-1) {stack.push(par+1);stack.push(right);}}
}
用栈来模拟,用栈后进先出的原理来模拟实现。
快速排序最好还是用递归来实现
五、时间空间复杂度
优化后的
时间复杂度:O(n*log2n)空间复杂度:O(log2n)稳定性:不稳定
相关文章:

JAVA-快速排序
目录 一、快速排序基本思想 二、快速排序的实现 1.Hoare法找基准值 2.挖坑法 3.前后指针法(了解) 三、快速排序的优化 1.三数取中法 2.递归到小的子区间时,可以考虑使用插入排序 四、非递归的写法 五、时间空间复杂度 一、快速排序基本思想 快速排序是 H…...
日志收集Day003
1.索引模板 查看所有索引模板 GET 10.0.0.101:9200/_template 2.查看单个索引模板 GET 10.0.0.101:9200/_template/.monitoring-es 3.创建索引模板 POST 10.0.0.101:9200/_template/lxctp {"aliases": {"DBA": {},"SRE": {},"K8S&qu…...

基于quartz,刷新定时器的cron表达式
文章目录 前言基于quartz,刷新定时器的cron表达式1. 先看一下测试效果2. 实现代码 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差&…...

数学大模型MAmmoTH:通过混合说明调整建立数学通才模型
向悦和陈文虎是该项目的主要作者。他们这个项目推出 MAmmoTH,这是一系列专为解决一般数学问题而定制的开源大型语言模型 (LLM)。 MAmmoTH 模型在 MathInstruct 上进行训练,MathInstruct 是我们精心策划的指令调整数据集。 MathInstruct 已编译 来自 13 个…...

Opencv学习
Long time no see!哈哈,假期终于有时间做一点自己喜欢的东西了 还是想说,每天花一点时间投在自己喜欢的事情上,或者专攻一些平时不学的方向,真的很酷! 图片绘制 对于图像绘制,可以分为:图像创…...

python生成图片和pdf,快速
1、下载安装 pip install imgkit pip install pdfkit2、wkhtmltopdf工具包,下载安装 下载地址:https://wkhtmltopdf.org/downloads.html 3、生成图片 import imgkit path_wkimg rD:\app\wkhtmltopdf\bin\wkhtmltoimage.exe # 工具路径,安…...
剑指Offer|LCR 044.在每个树行中找最大值
LCR 044.在每个树行中找最大值 给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。 示例 1: 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9] 解释:1/ \3 2/ \ \ 5 3 9 示例 2: 输入: root [1,2,3] 输出: [1,3] 解…...

PWM信号概述
什么是PWM信号? PWM(Pulse-width modulation)是脉冲宽度调制的缩写。 脉冲宽度调制是一种模拟信号电平数字编码方法。 脉冲宽度调制PWM是通过将有效的电信号分散成离散形式从而来降低电信号所传递的平均功率的一种方式。所以根据面积等效法…...
关于BAR(PCIE BAR或AXI BAR)的解释
假设某BAR的默认值是xxxx_0000(这里表示8个比特位),其中低4位不可写,可操作的最低位是4,所以该BAR的大小是2^416字节; 1、系统软件向BAR写0xFF 2、系统软件读BAR,读到的值是0xF0,于是…...

计算机的错误计算(二百二十一)
摘要 利用一个数学解题器化简计算 实验表明,即使是数学解题器,也是一派胡言。 有一读者来信,询问数学大模型的推理事宜。现就前面的案例继续做一讨论。 例1. 化简计算摘要中算式。 下面是与一个数学解题器的对话。 点评: &am…...
【力扣Hot 100】矩阵1
矩阵置零:1. 开两个数组判断该行/该列是否有0;2. 用第0行/第0列分别判断该列/该行是否有0 螺旋矩阵:记录方向,一直按某方向前进,遇到障碍方向就变一下 1. 矩阵置零 给定一个 *m* x *n* 的矩阵,如果一个元…...

移动端VR处理器和传统显卡的不同
骁龙 XR 系列芯片 更多地依赖 AI 技术 来优化渲染过程,而传统的 GPU 渲染 则倾向于在低画质下运行以减少负载。这种设计是为了在有限的硬件资源下(如移动端 XR 设备)实现高性能和低功耗的平衡。以下是具体的分析: 1. AI 驱动的渲染…...
「 机器人 」利用数据驱动模型替代仿真器:加速策略训练并降低硬件依赖
前言 在强化学习(Reinforcement Learning, RL)中,策略训练需要大量的交互数据(状态、动作、奖励、下一状态),而这些数据通常来自仿真器或真实硬件。传统高保真仿真器虽然能在一定程度上模拟飞行器的动力学,但往往计算量大、开发成本高,且仍可能与真实环境存在差距。为此…...

MATLAB 如何避免复杂shp文件对inpolygon的影响
**任务描述:**当我想用inpolygon函数将属于非洲的pixel选出来时,发现因为周边小岛的影响,pixel选取有问题,如下图。 第一种解决办法: 首先将复杂shp文件查分成简单的shp文件,即将不相交的元素分离开 [QGIS…...

【2024年华为OD机试】 (C卷,200分)- 贪吃的猴子(JavaScriptJava PythonC/C++)
一、问题描述 题目解析 问题描述 一只猴子来到果园,发现许多串香蕉排成一行,每串香蕉上有若干根香蕉。每串香蕉的根数由数组 numbers 给出。猴子每次只能从行的开头或末尾获取香蕉,并且只能获取 N 次。求猴子最多能获取多少根香蕉。 输入…...
PostgreSQL中级专家是什么意思?
数据库技术领域,PostgreSQL 作为一种广泛使用的开源关系型数据库管理系统,吸引了众多技术人员深入学习和研究。“PostgreSQL 中级专家” 是对掌握该数据库特定技能层次的一种描述。 知识储备 中级专家深入理解 PostgreSQL 的体系结构,包括进程…...
从根源分析,调试,定位和解决MacOS ld: unsupported tapi file type ‘!tapi-tbd‘ in YAML file
你要是遇到同样错误,找一圈都没有解决,建议认真读一下本文,这个应该是最终极的解决办法,从原理上剖析了产生的原因,同时给出来了调试和定位的办法。 maccos使用brew安装了一个gcc14, 结果编译一个最简单的程序都报错&a…...

【Uniapp-Vue3】previewImage图片预览
如果我们想要实现点击一张图片放大,并能够左右滑动,就要使用previewImage这个API。 uni.previewImage({ current:xxx, // 当前图片下标 urls:xxx, // 图片路径组 // 其他参数 }) 我们先编写一个点击图片的事件,并传递当前点击图片的下标&…...
doris:Insert Into Values
INSERT INTO VALUES 语句支持将 SQL 中的值导入到 Doris 的表中。INSERT INTO VALUES 是一个同步导入方式,执行导入后返回导入结果。可以通过请求的返回判断导入是否成功。INSERT INTO VALUES 可以保证导入任务的原子性,要么全部导入成功,要么…...
15 分布式锁和分布式session
在java中一个进程里面使用synchronized在new出来对象头信息中加锁,如果是静态方法中在加载的类信息中加锁(我们在锁的原理中讲过)。如果使用lock加锁可以自己指定。这些都是在同一个进程空间中的操作。如果在分布式环境中由于程序不在一个进程空间,就没办…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...