数据结构之排序了如指掌(三)

目录

题外话

正题

 快速排序

Hoare法

Hoare法思路

Hoare法代码详解

挖坑法

挖坑法思路

挖坑法代码

前后指针法

前后指针法思路

前后指针法代码

小结


题外话

我们接着把没有写完的排序内容完成,快速排序其实大同小异,大家好好把思路整理一下

正题

 快速排序

快速排序一共有三种方法

1.Hoare法

2.挖坑法

3.前后指针法

Hoare法

Hoare法是以快速排序创始人Hoaer命名的方法

Hoare法思路

这三种方法都是通过递归排序

1.首先我们创建left和right分别指向0下标和数组最后一个元素下标

2.先建立一个基准值0下标元素,先让right从右到左一个一个去找到比0下标元素小的元素,再让left从左到右去一个一个去找比0下标大的元素

3.当right找到比基准值小的元素,并且left也找到比基准值大的元素之后,我们让right下标元素和left下标元素交换

4.当left和right相遇之后,我们把基准值和其中任意一个下标元素交换,这样基准值左边的元素就比基准值小,基准值右边的元素就比基准值大

5.然后我们再给基准值左边设立left和right然后再去循环这个过程排序,基准值右边也是同理

如果不理解请看下图

看到这两幅图会不会有种二叉树的感觉呢,一层一层的去遍历排序就是这样


Hoare法代码详解

先说一下咱们这个写代码的框架

因为框架真的很重要!!

我们写代码的时候要尽量解耦合,并且提高扩展性

下图A方法中包含B方法

当我们要修改A方法的时候为了正常可以运行,可能会影响到B方法,还要去B方法里修改B方法

而当我们写代码的时候让A和B是一个独立的个体,再由C去调用他们,当修改A或者B中的任意一个代码的时候不会影响到另一方

我们本篇内容要写Hoare法,挖坑法和前后指针法

下面代码大家可以自己观察一下框架

我先列出我们要做的几件事

1.找到基准值,并且使基准值已经交换到数组中间位置

2.从找到的基准值左边去递归数组并排序,并且再次找左边基准值

3.从找到的基准值右边去递归数组并排序,并且再次找右边基准值

4.递归这个过程

代码详解

public void quickSort(int[] arr)
    {
        //调用quick方法并传参数
        quick(arr,0, arr.length-1);
    }


    private void quick(int[] arr,int start,int end)
    {
        //start如果大于等于end说明已经相遇,也说明当前这边已经排完序了
        if (start>=end)
        {
            return;
        }
        //调用Hoare法先让第一次的基准值到数组中间位置
        int pivot=partitionHoare(arr,start,end);
        //然后递归基准值左边并排序
        quick(arr,start,pivot-1);
        //递归基准值右边并排序
        quick(arr,pivot+1,end);
    }

    private int partitionHoare(int[] arr, int left, int right) {
        //先将基准值元素给到tmp
        int tmp=arr[left];
        //并将基准值下标给到i,以免找不到基准值下标,无法交换
        int i=left;
        //当left小于right时
        while (left<right)
        {
            //我们在此处while循环也需要加上left<right条件,否则left可能大于right
            //并且right下标元素大于等于基准值的时候right--
            while (left<right&&arr[right]>=tmp)
            {
                right--;
            }
            //走到这里说明right找到比基准值小的元素
            //left开始找比基准值大的元素,如果left下标元素小于基准值,left++
            while (left<right&&arr[left]<= tmp)
        {
            left++;
        }
            //走到这里说明left找到了比基准值大的元素,right找到了比基准值小的元素,此时将left元素和right元素交换
            //并继续进行while循环
            swap(arr,left,right);
        }
        //走到这里说明left和right相遇,则交换基准值元素和相遇点元素
        swap(arr,i,left);
        //交换之后,此时left就是基准值下标,返回即可
        return left;
    }
    //挖坑法
    private int partitionHole(int[] arr,int left,int right)
    {
        int tmp=arr[left];
        while (left<right)
        {
            while (left<right&&arr[right]>=tmp)
            {
                right--;
            }
            arr[left]=arr[right];

            while (left<right&&arr[left]<= tmp)
        {
            left++;
        }
            arr[right]=arr[left];
        }
        arr[left]=tmp;
        return left;
    }
//交换代码
 public void swap(int[] arr,int a,int b)
    {
        int tmp=arr[a];
        arr[a]=arr[b];
        arr[b]=tmp;
    }

挖坑法

挖坑法思路

1.将基准值保存在临时变量(相当于挖掉挖坑),并且从右边找比基准值小的,左边找比基准值大的

2.从右边找到比基准值小的,放入坑中,此时又出现一个新的坑

3.从左边找比基准值大的,放入坑中,此时又新出现一个坑

4.循环上述过程,当left和right相遇的时候,无论是谁相遇谁,left和right相遇位置一定会有个坑,然后把临时变量也就是基准值放入坑中

5.从左边建立新的基准值递归这个过程

6.从右边建立新的基准值递归这个过程

以上觉得我写的无法理解清楚,请看下图

所有的思路就是这样,就是先把基准值挖坑,然后从右边找,从左边找去填坑,然后相遇位置一定是坑,把基准值放入坑,递归左边和右边即可

挖坑法代码

public void quickSort(int[] arr)
{//调用quick方法并传参数quick(arr,0, arr.length-1);
}private void quick(int[] arr,int start,int end)
{//start如果大于等于end说明已经相遇,也说明当前这边已经排完序了if (start>=end){return;}//调用挖坑法,先让第一次的基准值到数组中间位置int pivot=partitionHole(arr,start,end);//然后递归基准值左边并排序quick(arr,start,pivot-1);//递归基准值右边并排序quick(arr,pivot+1,end);
}
private int partitionHole(int[] arr,int left,int right)
{//默认为最左边为基准值,将基准值挖坑放入临时变量int tmp=arr[left];//当left没有和right相遇while (left<right){//当left没有和right相遇并且right还没有找到比基准值小的元素while (left<right&&arr[right]>=tmp){//向左继续寻找right--;}//走到这说明找到了,然后把坑填上arr[left]=arr[right];//当left和right没有相遇,并且left没有找到比tmp大的元素while (left<right&&arr[left]<= tmp){//继续向右寻找left++;}//找到了,此时将right位置的坑填上arr[right]=arr[left];}//走到这里说明left和right相遇了,把基准值填入相遇点arr[left]=tmp;//返回基准值return left;
}

前后指针法

这个方法和上述两个方法略有不同

前后指针法思路

1.让0下标作为基准值

2.left指向0下标,right指向数组最后一个元素

3.创建prev指向left,创建cur指向prev+1

4.当cur没有走完数组最后一个元素,也就是cur<=right

5.让cur一直从左往右去找到比cur小的元素并且满足++prev!=cur,说明prev再往前走一个,此时prev等于cur

6.prev只有在cur找到比基准值小的元素才会往前走,而cur无论有没有找到prev都会往前走

7.prev没有往前走,也就说明了,cur往前走的时候,找到的元素大于基准值

8.如果满足上面条件,就交换cur和prev元素,cur继续往前走,直到走到right位置

9.当走完right,让基准值和prev元素交换,最后返回prev,继续递归遍历prev左边和prev右边

这就有一种cur推着prev走的感觉,只有cur满足条件,prev才有可能往后走

画个图大家就懂了

大家只要清楚的明白cur和prev的满足条件即可

前后指针法代码

public void quickSort(int[] arr)
{//调用quick方法并传参数quick(arr,0, arr.length-1);
}
private void quick(int[] arr,int start,int end)
{//start如果大于等于end说明已经相遇,也说明当前这边已经排完序了if (start>=end){return;}//先让第一次的基准值到数组中间位置int pivot=partition(arr,start,end);//然后递归基准值左边并排序quick(arr,start,pivot-1);//递归基准值右边并排序quick(arr,pivot+1,end);
}
private int partition(int[] arr,int left,int right)
{//让prev指向leftint prev=left;//cur指向prev+1int cur=prev+1;//当cur没有走完rightwhile (cur<=right){//重点!!  如果cur中的元素比基准值小并且++prev后所在的位置不是cur的位置if (arr[cur]<arr[left]&&arr[++prev]!=arr[cur]){//才会交换prev和cur元素值swap(arr,prev,cur);}//cur不管满不满足以上条件都会往后走,而prev只有满足arr[cur]<arr[left]这个条件,才会往后走,因为是短路与//前面条件不满足,不会进行后面条件判断cur++;}//当cur走完right位置,就把基准值和prev交换位置,返回基准值下标swap(arr,left,prev);return prev;
}

小结

我们可以看这三个方法代码,他们被调用的时候都是通过quick去调用,而且调用三个方法的时候只需要把调用方法名字修改一下就可以了,很方便

我们已经讲完了

直接插入排序(摆扑克牌)

希尔排序(分组摆扑克牌)

冒泡排序(相邻两个元素只要左边比右边大就交换位置,每趟会将数组现存最大元素放到最后面)

堆排序(建立大根堆,然后堆顶元素必然是堆中最大的元素,然后将堆顶元素和最后一个元素交换位置,除去交换的元素,将交换后的堆重新建立大根堆并循环以上过程)

选择排序(找基准值然后排序,再从基准值左边找基准值排序,再从基准值右边找基准值排序)

昨晚熬了个小夜,今天更要加油努力!!!!

喜欢的话记得给个三连!!!(点赞关注收藏)

有问题请在评论区留言或者私信!!

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

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

相关文章

蓝桥杯:握手问题和小球反弹问题

试题 A: 握手问题 本题总分&#xff1a; 5 分 【问题描述】 小蓝组织了一场算法交流会议&#xff0c;总共有 50 人参加了本次会议。在会议上&#xff0c; 大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手&#xff08;且仅有一次&#x…

论文笔记:Teach LLMs to Phish: Stealing Private Information from Language Models

iclr 2024 reviewer 评分 588 1 intro 提出了一种“神经网络钓鱼攻击” 一种新的针对在敏感用户数据上训练或finetune的LLMs的攻击向量攻击者将看似无害的投毒数据插入到模型的训练数据集中&#xff0c;以“教会LLMs进行钓鱼”&#xff0c;即诱导模型记住他人的个人身份信息&…

Linux(Ubuntu) 查看并删除使用【dpkg】安装的软件【mysql 8.3安装失败---原因调查】

目录 ■前言 ■查看安装的软件 ■删除安装的软件 正常删除&#xff08;dpkg -r xxxxName&#xff09; 问题解决&#xff1a;use --purge to remove them too ■其他调查信息 命令 图片1 图片2 图片3 图片4 ■前言 安装Mysql8.3失败 我的服务器-CSDN博客 ■查看安…

结合 react-webcam、three.js 与 electron 实现桌面人脸动捕应用

系列文章目录 React 使用 three.js 加载 gltf 3D模型 | three.js 入门React three.js 3D模型骨骼绑定React three.js 3D模型面部表情控制React three.js 实现人脸动捕与3D模型表情同步结合 react-webcam、three.js 与 electron 实现桌面人脸动捕应用 示例项目(github)&…

【linux深入剖析】深入理解软硬链接 | 动静态库的制作以及使用

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1.理解软硬链接1.1 操作观…

CCF区块链论文录用资讯--ICDE 2024

ICDE是CCF A类会议 (数据库&#xff0f;数据挖掘&#xff0f;内容检索) 其2024录用了8篇区块链论文 Database technology for Blockchains I Efficient Partial Order Based Transaction Processing for Permissioned Blockchains &#xff08;针对许可区块链的高效的基于偏序…

【算法】回溯:与递归,dfs的同质与分别,剪枝与恢复现场的详细理解,n皇后的回溯解法及算法复杂度分析。

目录 ​编辑 1.什么是回溯 2.关于剪枝 3.关于恢复现场 4.题目&#xff1a;二叉树的所有路径&#xff08;凸显恢复现场&#xff1a;切实感受回溯与深搜&#xff09; 问题分析 ①函数设置为&#xff1a;void Dfs(root) ②函数设置为&#xff1a;void Dfs(root,path) 解题思想&…

webpack or vite? vuex or pinia?

2022.2.18, 新建一个vue3的项目&#xff0c;过程如下&#xff1a; 目录结构如下&#xff1a; 当还在犹豫选择webpack还是vite&#xff0c;vuex或者pinia的时候&#xff0c;尤大大已经给出了默认选择&#xff0c;vite && pinia。

分布式ID的方案和架构

超过并发&#xff0c;超高性能分布式ID生成系统的要求 在复杂的超高并发、分布式系统中&#xff0c;往往需要对大量的数据和消息进行唯一标识如在高并发、分布式的金融、支付、餐饮、酒店、电影等产品的系统中&#xff0c;数据日渐增长&#xff0c;对数据分库分表后需要有一个唯…

【Linux】阿里云ECS搭建lnmp和lamp集群

搭建LNMP&#xff08;Linux Nginx MySQL PHP&#xff09;或LAMP&#xff08;Linux Apache MySQL PHP&#xff09;集群 创建ECS实例&#xff1a; 在阿里云控制台创建多个ECS实例&#xff0c;选择相应的操作系统和配置&#xff0c;确保这些实例在同一VPC网络内&#xff0c;…

Golang | Leetcode Golang题解之第28题找出字符串中第一个匹配项的下标

题目&#xff1a; 题解&#xff1a; func strStr(haystack, needle string) int {n, m : len(haystack), len(needle)if m 0 {return 0}pi : make([]int, m)for i, j : 1, 0; i < m; i {for j > 0 && needle[i] ! needle[j] {j pi[j-1]}if needle[i] needle[…

安全加速SCDN带的态势感知能为网站安全带来哪些帮助

随着安全加速SCDN被越来越多的用户使用&#xff0c;很多用户都不知道安全加速SCDN的态势感知是用于做什么的&#xff0c;德迅云安全今天就带大家来了解下什么是态势感知&#xff0c;态势感知顾名思义就是对未发生的事件进行预知&#xff0c;并提前进行防范措施的布置&#xff0…

机器学习(31)PINN

文章目录 摘要Abstract一、监督学习二、文献阅读1. 题目2. abstract3. 偏微分方程的数据驱动解3.1连续时间模型example(Schrodinger equation)&#xff1a; 3.2离散时间模型Example (Allen–Cahn equation)&#xff1a; 4. 文献解读4.1 Introduction4.2 创新点 三、实验内容1.实…

车载电子电器架构 —— 电子电气架构开发总结和展望

车载电子电器架构 —— 电子电气架构开发总结和展望 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要…

【web网页制作】html+css旅游家乡山西主题网页制作(3页面)【附源码】

山西旅游网页目录 涉及知识写在前面一、网页主题二、网页效果Page1、景点介绍Page2、酒店精选|出行攻略Page3、景色欣赏 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 四、网页源码4.1 主页模块源码4.2 源码获取方式 作者寄语 涉及知识 山西旅游主题网页制作&am…

为什么光伏探勘测绘需要无人机?

随着全球对可再生能源需求的不断增长&#xff0c;光伏产业也迎来了快速发展的机遇。光伏电站作为太阳能发电的主要形式之一&#xff0c;其建设前期的探勘测绘工作至关重要。在这一过程中&#xff0c;无人机技术的应用正逐渐展现出其独特的优势。那么&#xff0c;为什么光伏探勘…

Java调用http接口的几种方式(HttpURLConnection、OKHttp、HttpClient、RestTemplate)

Java作为后端语言是开发接口实现功能供客户端调用接口&#xff0c;这些客户端中最主要是本项目的前端&#xff1b;但有时候也需要Java请求其他的接口&#xff0c;比如需要长连接转短链接&#xff08;请求百度的一个接口可以实现&#xff09;、获取三方OSS签名、微信小程序签名、…

IDEA 使用备忘录(不断更新)

IDEA 项目结构&#xff08;注意层级结构&#xff0c;新建相应结构时&#xff0c;按照以下顺序新建&#xff09;&#xff1a; project&#xff08;项目&#xff09; module&#xff08;模块&#xff09; package&#xff08;包&#xff09; class&#xff08;类&#xff09; 项…

公布应用程序

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d8;相关专栏Rust初阶教程、go语言基础系列、spring教程等&#xff0c;大家有兴趣的可以看一看 &#x1f4d9;Jav…

【Vue】新手一步一步安装 vue 语言开发环境

文章目录 1、下载node.js安装包 1、下载node.js安装包 1.打开node.js的官网下载地址&#xff1a;http://nodejs.cn/download/ 选择适合自己系统的安装包&#xff1a;winds、mac 2. 配置node.js和npm环境变量 安装好之后&#xff0c;对npm安装的全局模块所在路径以及缓存所在路…