Java中的快速排序

news2024/11/16 5:58:19

快速排序

  • 递归版本
    • 挖坑法
    • Hoare法
    • 优化
  • 非递归

相信即使大家并不知道快速排序究竟是个啥,但也一定听说过快排,今天我来给兄弟们讲讲快速排序!

递归版本

在这里插入图片描述
快速排序的思想就是找基准,就比如我们以数组中的第一个数字12为基准,我们从最后往前面找,如果找到一个比12小的数字就用它覆盖12,但是如果我们不提前储存一份12的话,后面就找不到这个数据了,我们使用覆盖的话就是使用的挖坑法,此时场上有两个9,这是显然不可以的,所以我们就从头开始往后面找,找到一个比12大的数字放到9位置…最后达到的效果必然是左右相遇,那么前面的就全都是比基准小的数字,后面都是比基准大的数字了.

挖坑法

在这里插入图片描述
在这里插入图片描述
第一趟找基准找好了,然后呢?我们现在已经确定了一个位置,那这个位置的左右是不是可以使用同样的方法递归下去呢?递归条件就是左边不能跑到右边去.

		//这里是为了参数的统一才
    public void quickSort(int[]arr){
        quick(arr,0,arr.length-1);
    }
    
    private void quick(int[]arr,int left,int right){
    	//递归的终止条件
        if(left>=right)return;
        int index=partition1(arr,left,right);
        quick(arr,left,index-1);
        quick(arr, index+1,right);

    }


    
    private int partition(int[] array,int left,int right){
        int tmp=array[left];
        //在找基准的时候,有很大可能是要进行多次数据调整的
        while(left<right){
            while(left<right&&array[right]>=tmp){
            //找数据的时候也不能够越界,还有就是这里的还有下面的等号
            //至少要写一个,不然会前后相同的数据反复交换
                right--;
            }
            swap(array,left,right);
            while(left<right&&array[left]<=tmp){
                left++;
            }
            swap(array,left,right);
        }
        //从循环出来就意味着左右相遇了
        array[left]=tmp;
        return left;
    }

Hoare法

挖坑法是事先留好基准的那个坑,最后再给填上,Hoare法就是先找,后面找到小的停下来,前面找到大的停下来,然后交换,要知道的是,Hoare就不是覆盖了,而是交换.
那兄弟们有没有想过,为什么不论是挖坑还是Hoare我们都是先从后面开始找比基准小的呢?因此如果我们先从前面找比基准大的数字的话,最后停下的位置找到的一定是比基准大的,交换完成后,大的就到前面了,这可不行!

    private int partition1(int[] array,int left,int right){
        int tmp=array[left];
        int i=left;
        while(left<right){
            while(left<right&&array[right]>=tmp){
                right--;
            }
            while(left<right&&array[left]<=tmp){
                left++;
            }
            swap(array,left,right);
        }
        swap(array,i,left);
        return left;
    }

优化

在这里插入图片描述
我们考虑极端情况下,数据已经有序,此时我们递归的深度会很大:
在这里插入图片描述
如果数据很大的情况下,很有可能就会栈溢出,所以我们希望的情况是,每一次我们找到的基准都是相对中间的数字,这样子我们左右都会处于一种相对平衡的状态:
在这里插入图片描述
但是从我们刚才的代码中可以发现,每一次我们找的基准都是从最左边开始的,如果我们的人品不错,那么我们可以考虑从数组中随机选取一个数字,就以这个数字为基准开始找它位置,可是如果运气不太好的话,我们还是会造成上述的问题,因此我们可以使用三数取中法,首尾加中间的,这样子三数取中间作为基准的话,左右两边不至于有一边是空的.找到中间数之后和最左边的数字交换即可:

    private  int getMid(int[]arr,int left,int right){
        int mid=(left+right)/2;
        if(arr[left]>arr[right]){
            if(arr[mid]>arr[left]){
                return left;
            }else if(arr[right]>arr[mid]){
                return right;
            }else {
                return mid;
            }
        }else {
            if(arr[mid]>arr[right]){
                return right;
            }else if(arr[left]>arr[mid]){
                return left;
            }else {
                return mid;
            }
        }
    }

我们还可以利用插入排序越有序越快的特性再进行优化,我们知道指数增长越到后面越是可怕,所以当我们运行到一定程度的时候,是不是数据已经趋于有序了,那此时我们直接上插入排序,排完return走人:

    private void quick(int[]arr,int left,int right){
        if(left>=right)return;
        if(right-left+1>3){
            insertSort1(arr,left,right);
            return;
        }
        int midIndex=getMid(arr,left,right);
        swap(arr,midIndex,left);
        int index=partition1(arr,left,right);
        quick(arr,left,index-1);
        quick(arr, index+1,right);

    }

非递归

一般来说非递归的方法使用起来就是循环了,此时我们需要使用到栈,使用栈的原因是因为要记录下每次快排的起始和结束位置:

    public void quickSortNonR(int[] arr, int left, int right) {
        Stack<Integer>stack=new Stack<>();
        //基准方法不光是找到基准的位置,还会为我们直接在原数组上动刀
        int index=partition(arr,left,right);
        //首先我们必须给栈一个数据才可以
        stack.push(0);
        stack.push(index-1);
        stack.push(index+1);
        stack.push(right);

        while(!stack.empty()){
            int end=stack.pop();
            int start=stack.pop();
            int par=partition(arr,start,end);
          //只有一个数据的话就已经有序了,不需要再排序
            if(par-start>1){
                stack.push(start);
                stack.push(par-1);
            }
            if(end-par>1){
                stack.push(par+1);
                stack.push(end);
            }
        }
    }

希望我的这篇博客能够帮助到大家!
百年大道,你我共勉!!!

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

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

相关文章

Linux—InstallOS-RedHat9.1

下载https://developers.redhat.com/products/rhel/download 需注册账号。安装正常安装就行。安装注意事项&#xff1a;(1)Software SelectionCentOS的摘录过来&#xff0c;通用。最小安装&#xff08;Minimal Install&#xff09;这个选项只提供运行CentOS 的基本软件包。最小…

Python学习-----起步4(列表元素的添加,删除,修改,查询,获取长度)

目录 前言&#xff1a; 列表元素的添加&#xff08;或者叫写入&#xff09; 1.append&#xff08;&#xff09;函数 2.extend&#xff08;&#xff09;函数 3.insert()函数 列表元素的删除 1.remove() 函数 2. pop() 函数 3.clear&#xff08;&#xff09;函数 4.del …

公司40岁的程序員到底在写什么代码

去年在前公司玩了一年&#xff08;基本兩三個月一個需求&#xff09;&#xff0c;除了日常維護就一些特別簡單的功能開發&#xff0c;到年底也沒見到公司黃&#xff08;國企背景&#xff09;&#xff0c;沒辦法只好裸辭&#xff0c;現在這個公司各方面还不错&#xff0c;但是令…

Cookie、Session、Token、JWT只看这一篇文章就够了

什么是认证&#xff08;Authentication&#xff09; 通俗地讲就是验证当前用户的身份&#xff0c;证明“你是你自己”&#xff08;比如&#xff1a;你每天上下班打卡&#xff0c;都需要通过指纹打卡&#xff0c;当你的指纹和系统里录入的指纹相匹配时&#xff0c;就打卡成功&a…

MongoDB Map Reduce

在用 MongoDB 查询时&#xff0c;若返回的数据量很大&#xff0c;或者做一些比较复杂的统计和聚合操作做花费的时间很长时&#xff0c;可以使用 MongoDB 中的 mapReduce 进行实现。mapReduce 是个灵活且强大的数据聚合工具&#xff0c;它的好处是可以把一个聚合任务分解为多个小…

设计模式(三)----创建型模式之单例模式(一)

一、创建型模式 创建型模式的主要关注点是“怎样创建对象&#xff1f;”&#xff0c;它的主要特点是“将对象的创建与使用分离”。 这样可以降低系统的耦合度&#xff0c;使用者不需要关注对象的创建细节。 创建型模式分为&#xff1a; 单例模式 工厂方法模式 抽象工厂模式…

英语学习 3

1 词汇积累 1、ships 船 2、class 级 3、marvels 奇迹 4、marvelous 非凡的、了不起的、极好的 5、cursed 诅咒、被诅咒的 6、the most luxurious ships 最豪华的船 7、luxury 奢侈、奢华的 8、luxurious 心满意足的、舒适的 9、utmost 极度的、最大的 10、kind 种类 11、voya…

Kali Linux神秘工具教程(详细版)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、Kali Linux - 安装和配置信息收集工具二、NMAP隐形扫描搜索Searchsploit域名系统工具dnsenum.plDNSMAPdnstracerLBDHping3漏洞分析工具Cisco-torch工具Cisco…

回溯算法(基础)

目录 一、基本概念 二、以简单全排列认识回溯 &#xff08;一&#xff09;决策树 &#xff08;二&#xff09;回溯示意图 &#xff08;三&#xff09;核心代码 &#xff08;四&#xff09;完整代码 三、组合问题 &#xff08;一&#xff09;问题 &#xff08…

如何通过groovy扩展方法

最近一直使用jmeter做接口测试&#xff0c;虽然好用&#xff0c;但是每次解析结果都要写大量重复代码。然后想到groovy是可以在运行时动态增强jvm字节码的&#xff0c;比如Date中就有大量增强的方法&#xff0c;比如format,upto,downto......&#xff0c;既然groovy可以&#x…

用 NFTScan 的角度解析 Yuga labs NFT 项目系列

如果要说 NFT 影响力最大的公司是哪个&#xff1f;如果说是 Yuga Labs 应该我想大家应该都不会否认。一个创立一年多的 NFT 营销和开发公司&#xff0c;多次的并购以及行销操作都立下 NFT 界的标竿典范&#xff0c;尤其 BAYC NFT 系列取得巨大成功之后&#xff0c;该团队已成为…

DSP_定义一个大的全局数组_探索之路

前言 最近在做基于dsp平台的无通信接口系统辨识&#xff0c;辨识的时候会有很大的数据需要存到一个数组当中&#xff0c;而dsp如果定义一个很大的全局数组&#xff0c;编译会报错。 本文将探索如何解决这个报错以及全局数组的大小极限。 正文 首先&#xff0c;我们定义了一个…

数学库:Extreme Optimization Numerical 8.1.4 Crack

Extreme Optimization Numerical.NET 的极端优化数值库&#xff0c;更快地构建金融、工程和科学应用程序&#xff0c;具有置信度和预测带的非线性曲线拟合&#xff0c;用于 .NET的极端优化数值库是为 Microsoft .NET 框架构建的通用数学和统计类的集合。用于 .NET的极端优化数值…

将无风险资产与单个风险资产进行组合

目录 1. 基本概念 2. 将无风险资产与单个风险资产进行组合 3. 有效资产组合 1. 基本概念 无风险资产和风险资产。 我的理解&#xff1a;无风险资产利率完全可确定&#xff0c;风险资产的利率称为预期收益率&#xff0c;并且有标准差。 关于风险资产预期收益率和标准差的计…

NC65 自由报表发布为节点如何显示以及如何取消已发布的报表节点

NC65 自由报表发布为节点如何显示以及如何取消已发布的报表节点&#xff1f; 一、NC65 自由报表发布为节点如何显示&#xff1f; 答&#xff1a;需要在动态建模平台-权限管理-职责管理下的职责节点进行功能分配&#xff0c;如下图&#xff1a; 二、如何取消已发布的报表节…

Javac Spire.Presentation 之PPT文本图片内容提取

目录结构前言文档准备引入Maven依赖代码块提取结果验证ppt_demo.ppt 提取结果pptx_demo.pptx 提取结果前言 应公司需求&#xff0c;需实现以下功能 PPT文本内容的替换&#xff1b;PPT文本内容的提取&#xff1b;PPT中图片的提取存放&#xff1b; 此文章将使用Spire.Presenta…

Mal-PEG-SCM,Maleimide PEG SCM,双功能修饰性PEG

Mal-PEG-SCM&#xff0c;SCM-PEG-Maleimide&#xff0c;Maleimide PEG SCM&#xff0c;Maleimide PEG Succinimidyl Carboxymethyl Ester马来酰亚胺-聚乙二醇-琥珀酰亚胺羧甲基酯&#xff0c;马来酰亚胺PEG琥珀酰亚胺羧甲基酯Product specifications&#xff1a;1.CAS No&#…

DataGrip下载安装及使用教程(详细版)

一.安装教程 1.下载 官网下载&#xff1a;DataGrip: The Cross-Platform IDE for Databases && SQL by JetBrains 2.点击Download跳转到下载页面 3.下载最新版本的可以直接点击 Download 下载&#xff0c;下载其他版本的点击 Other versions 下载其他版本 4. 4.选择…

改变Linux文件权限、所属用户组、所有者知识总结

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Linux操作…

requestAnimationFrame详解-js性能优化

requestAnimationFrame 请求动画帧 它是一个浏览器的宏任务 requestAnimationFrame的用法与settimeout很相似&#xff0c;只是不需要设置时间间隔而已。requestAnimationFrame使用一个回调函数作为参数&#xff0c;这个回调函数会在浏览器重绘之前调用。它返回一个整数&#x…