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

news2024/10/7 20:36:31

目录

题外话

正题

 快速排序

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指向left
    int prev=left;
    //cur指向prev+1
    int cur=prev+1;
    //当cur没有走完right
    while (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.coloradmin.cn/o/1610762.html

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

相关文章

HarmonyOS 状态管理

在声明式 UI 框架中&#xff0c;数据的改变触发 UI 的重新渲染。在 ArkUI 中不是所有数据的变化都会触发 UI 重新渲染&#xff0c;只有 状态变量 才会引起 UI 重新渲染。 状态变量 状态变量&#xff1a; 指被状态装饰器装饰的变量&#xff0c;只有这种变量的改变才会引起 UI …

(2022级)成都工业学院数据库原理及应用实验七: 数据库安全

写在前面 1、基于2022级软件工程/计算机科学与技术实验指导书 2、成品仅提供参考 3、如果成品不满足你的要求&#xff0c;请寻求其他的途径 运行环境 window11家庭版 Navicat Premium 16 Mysql 8.0.36 实验要求 1、创建数据库hospital,在hospital数据库中创建科室表De…

第一个STM32F767IGT6核心板

一. 制作原因 起先是因为参加计算机设计大赛准备的板子&#xff0c;其作用是连接OV5640摄像头来识别车牌号&#xff0c;主要外设有摄像头&#xff0c;SDRAM&#xff0c;网口等。 二. 原理图和PCB 原理图 PCB 三. 测试 1. 测试SDRAM功能 按下按键我们可以在串口中看到内存…

LTspice/Simplis仿真代码使用

LTspice/Simplis仿真代码使用 HI uu们 HI uu们,关注我的uu经常看到我上面贴了很多仿真代码,但是不知道怎么用. 今天来介绍下仿真代码怎么用, 比如说,我们用OP07做了一个跟随器,如图1所示. 图1:OP07跟随器 他的仿真代码非常简单,如下所示 XU1 N002 vout N001 N003 vout LT…

【Linux】详解进程通信中信号量的本质同步和互斥的概念临界资源和临界区的概念

一、同步和互斥的概念 1.1、同步 访问资源在安全的前提下&#xff0c;具有一定的顺序性&#xff0c;就叫做同步。在多道程序系统中&#xff0c;由于资源有限&#xff0c;进程或线程之间可能产生冲突。同步机制就是为了解决这些冲突&#xff0c;保证进程或线程之间能够按照既定…

都以为他是自杀20年后遗书曝光才明白张国荣的离世不简单

在时光的长河中&#xff0c;有些瞬间如同流星划过天际&#xff0c;短暂却又璀璨夺目。二十年前的那个春天&#xff0c;一个灵魂从这个喧嚣世界悄然离去&#xff0c;留下无尽的叹息与疑问。他就是张国荣——一位被誉为“风华绝代”的巨星。许多人曾认定他的离开是一场悲剧性的自…

计算机网络 -- 多人聊天室

一 程序介绍和核心功能 这是基于 UDP 协议实现的一个网络程序&#xff0c;主要功能是 构建一个多人聊天室&#xff0c;当某个用户发送消息时&#xff0c;其他用户可以立即收到&#xff0c;形成一个群聊。 这个程序由一台服务器和n个客户端组成&#xff0c;服务器扮演了一个接受…

element-ui合计逻辑踩坑

element-ui合计逻辑踩坑 1.快速实现一个合计 ​ Element UI所提供的el-table中提供了方便快捷的合计逻辑实现&#xff1a; ​ https://element.eleme.cn/#/zh-CN/component/table ​ 此实现方法在官方文档中介绍详细&#xff0c;此处不多赘述。 ​ 这里需要注意&#xff0c…

Don‘t fly solo! 量化之路,AI伴飞

在投资界&#xff0c;巴菲特与查理.芒格的神仙友谊&#xff0c;是他们财富神话之外的另一段传奇。巴菲特曾这样评价芒格&#xff1a;他用思想的力量拓展了我的视野&#xff0c;让我以火箭的速度&#xff0c;从猩猩进化到人类。 人生何幸能得到一知己。如果没有这样的机缘&…

每日学习笔记:C++ STL算法之容器元素变序

目录 反转元素次序 reverse(beg, end) reverse_copy(srcBeg, srcEnd, destEnd) 旋转元素 旋转&#xff1a;rotate(beg, newBeg, end) 复制同时旋转&#xff1a;rotate_copy(srcBeg, srcNewBeg, srcEnd, destBeg) 对元素做排列组合情况列举与切换 next_permutation(beg, …

国产化里程碑:明道云HAP私有部署版获信创评估证书,荣登会员单位

近期&#xff0c;明道云HAP私有部署版荣获信创产品评估证书&#xff0c;这一成就不仅标志着我们在信创领域的深入布局和持续努力获得了行业的广泛认可&#xff0c;也是对我们积极拥抱和推动国产化技术发展的肯定。更值得一提的是&#xff0c;我们还被授予“成员单位”的称号&am…

基于通达信---做T专用算法

什么是做T? 股票做T是股票市场中常见的一种投资策略,也就是股票进行T+0操作,通过当天买进的股票,在当天卖出,是股市中常见的一种超短线的操作。其中T就是指交易日,利用交易日中的股票涨跌来赚取差价。股票做T常见的类型就是正T和倒T。 1、正T 股票做正t就是指先买后卖,…

Rokid AR Lite空间计算套装发布,中国空间计算踏上差异化领先之路

动动手指、动动眼睛就可以“操控一切”&#xff0c;这种颇具科幻感、未来感的交互方式&#xff0c;令许多人感叹“未来已来”。而这令人震撼的变革背后&#xff0c;正是空间计算技术的迅猛崛起与广泛应用&#xff0c;使得这种曾经只存在于想象中的交互方式&#xff0c;如今正逐…

快速访问github

修改本地hosts文件 GitHub访问慢的原因在于域名解析&#xff0c;通过修改本地的hosts文件&#xff0c;将远程DNS解析改为本地DNS解析。 fang 步骤1&#xff1a;打开hosts文件&#xff08;没有就创建&#xff09; host所在位置&#xff1a; C:\Windows\System32\drivers\etc…

linux jenkins 2.89.1 安装部署 持续构建svn下maven项目并部署到tomcat

从这边博文可以学习到&#xff1a; jenkins的安装修改主目录初始化新建任务&#xff0c;构建第一个maven项目将构建完成的项目部署到tomcat Jenkins的安装相当简单&#xff0c;只需要从官网下载war包&#xff0c;放入tomcat&#xff0c;运行tomcat就可以访问Jenkins了 准备工作…

PyCharm,终端conda环境无法切换的问题(二个解决方案)

问题 PyCharm终端&#xff0c;环境切换无效&#xff0c;默认始终为base 解决一 Settings->Tools->Terminal->ShellPath&#xff0c;将powershell修改为cmd.exe 解决二 conda config --show在输出中找到 auto_activate_base 的行&#xff0c;发现被设置为 true&#x…

数据结构-双链表(图解)

目录 双链表&#xff08;Double-Linked List&#xff09;的概念与基本特性 一、双链表的基本组成 二、双链表的主要特性 三、双链表的操作 代码展示 malloc开辟函数 解析 初始化 解析 头插 解析 尾插 解析 头删 解析 尾删 解析 pos之后插入 解析 pos删除 …

抖音小店无货源怎么做?教你新店快速起店新攻略,你还在等什么?

大家好&#xff0c;我是电商花花。 从我关注抖音小店这个风口到现在已经有很长时间了&#xff0c;从了解到实操到复盘&#xff0c;陆陆续续将多家单店店铺月营业额达到数百万。 目前团队运营着80多家店铺&#xff0c;人均管理3-5个店铺&#xff0c;大部分店铺月营业额都在5W-…

【C++】飞机大战项目记录

源代码与图片参考自《你好编程》的飞机大战项目&#xff0c;这里不进行展示。 本项目是仅供学习使用的项目 飞机大战项目记录 飞机大战设计报告1 项目框架分析1.1 敌机设计&#xff1a;1.2 玩家飞机控制&#xff1a;1.3 子弹发射&#xff1a;1.4 游戏界面与互动&#xff1a;1.5…

文本美学:text-image打造视觉吸引力

当我最近浏览 GitHub 时&#xff0c;偶然发现了一个项目&#xff0c;它能够将文字、图片和视频转化为文本&#xff0c;我觉得非常有趣。于是我就花了一些时间了解了一下&#xff0c;发现它的使用也非常简单方便。今天我打算和家人们分享这个发现。 项目介绍 话不多说&#xf…