快速排序(挖坑法 前后指针法 非递归版本)

news2025/4/9 14:04:42

上一次我们说了快速排序的hoare的版本,但是该版本有很多问题,首先是需要控制很多边界,比较复杂一点

其次就是上一次的快速排序还是有很多的其他问题

我们试着想一下,如果我们用快速排序拍有序数组,那会怎么样?或者是重复特别多的会怎么做?

我们可以试着画一下图片

28c9fcc7abca444ebb5f2a315a707be1.png

如果是这样的一组顺序,那么首先我们取得key就是第一个位置,9 然后我们就要先从右边开始走,找比 9小的数字,我们直到找到9所属的位置才能停下来,然后我们把9和1交换,那么我们这一次的时间复杂度就是n

38ea35f4b4574bd599e72ede11b42777.png

然后就会这样,时间复杂度会立马变成n²

后面可以自己试着画一下

那么要怎么解决目前的这个问题呢?

我们可以想一下,如果我们每一次选择的key都不是该数组中最大或者最小的数,那么就可以避免这种问题

解决方法

1.采用随机选数法,我们可以用rand( ) 函数随机选择数组中的某个数字,然后让他和最左边的数字交换就可以了,这样就可以解决有序数组用快排的问题了,但是由于随机数不确定,不免有时候也会随机到最大或者最小的数字,所以它还不是最优的

2.我们可以采用“三数取中”,正如他的名字一样,我们在三个数字中选择值为中间的数字,然后交换,这样的话,如果是有序数组的话,那么三数取中是最优的,其次三数取中,也可以避免选取到最大或者最小的数字

那么如何实现呢?

下面我们就直接看代码

7bd8c3118bde4311a4bc4974617e4a5d.png

这次我们稍微看一下整体的逻辑,请看下面的代码

1da3485b2c6146dbb9d59b9a233c151e.png 

64aaa325a6414958a755a8a3f69fdd74.png 

这次我们直接在快排这个函数里面调用我们的hoare版本的快速排序,然后利用返回值,记录key的位置,然后继续递归,其中在hoare版本的快排中,我们中间使用了三数取中

上面这个我相信都能看明白

下面我们在介绍一个快排,挖坑法

挖坑法

c18ba76038014feca0b0a56cb36035e0.png

我们还是先看一下思想,其实这个的思想和hoare差不多,但还是有一些区别的

下面我们就看一下

首先我们就是和上面图片是一样的,我们先把key这个值记录起来,然后先右边找小,然后再左边找大

看图片

然后右边找小,找到了,然后把r位置的数字放在坑位,然后坑位到了r下面

a23a75043a414f63bbb74f1088edd333.png 

 然后就是左边找大

a73f14805b8649518df456afea34fbd3.png

 同样是找到了,放在坑位,然后坑位变化

15023c8adb304ba1b602488760fab295.png

 请继续看

d09855406b1c4cd3a591dd9d43281ff5.png

 👀

813363c8184546f5b8ec8a9b19c1d2d8.png

请 👀

38b9e3b41d7c48d18c37db1e75ee8cbe.png

 最后就把6的左边都是比他小的,6的右边都是比他大的,所以一趟排序就结束了,剩下的递归就是和hoare版本一样了

所以我们剩下就直接看代码

0e4760f020c14a2fbe1c3d5fb12cdc4f.png

其中上面就是一趟排序

 我们先记录key的值,然后再记录一下坑位,然后我们就是右边找大,然后左边找小,放在坑位里,等到了最后相遇的时候我们就出了循环,但是坑位我们还没有吧key放进去,所以我们放进去,最后我们返回坑位置的下标就行

f8bc3fcd3eec46c1aa805082bf0b9f2c.png

然后我们调用该函数,递归就行

 下面我们就讲一下前后指针法

前后指针法和前面两个版本的实现是有差别的,但是写起来是比较容易的

所以下面就来看一下前后指针法

我们还是看一趟排序的思路

969aa5a057024f13a31b7c253b2a20cd.png

刚开始的时候我们定义两个指针,一个指向第一个元素,还有一个指向第二个元素

然后我们就向下看

我们看cur的值是否大于keyi的值,如果大于的话就让cur加加,如果cur和prev都小于的话就让她们两个同时加加,如果prev大于key的值,但是cur小于key的值,那么就交换

下面看图片

 95c8698b993d4b00b076ba8745cc4032.png

首先我们就到了cur的值大于key的值,然后就让cur++就可以了

fb519294e20b485c873e5dc5c5072f76.png 

然后就走到了3的位置,然后cur就和prev交换

就是上面这样

0c5ed4f01adf4dfbabd701cb6e56541d.png 

然后继续向前推进

76f7972657014ebd937c7837890e0949.png 

cc7a6fe6dc7848749e12c11641a97999.png 

0e4526180f88480188e43d9e29fb52fe.png 

直到最后,cur大于最右边这时候让key和prev位置交换就行了

下面我们就看一下代码

6532e3fc7f2d4835b007d620479e1b46.png 

我们先定义key,然后再定义prev和cur的位置,这时候我们就进去循环,cur要小于right,这时候我们就开始判断,我们可以看到,我们不论怎么样cur都需要++那么我们就把cur++放在判断的外面,循环里面,这时候我们只需要判断prev什么时候++就可以了,如果我们的cur小于key的值,这时候我们的prev就++,如果这时候的prev 如果不等于cur的话(大于key),那么就交换

就是这样

下面我们就看一下非递归如何快排

我们先看思想

如果我们想非递归的话,那么我们要怎么做?

首先我们直接用循环肯定是不可能的,这时候我们就可以使用栈,或者队列都可以

那么我们应该怎么做呢?

下面来和我一起看一下

36567de0063c4227968042896fc0369f.png

假设我们用栈来实现非递归,并且我们要排序的是十个数字

下面我们就来看一下

我们先想一下我们的递归是如何递归的,我们刚开始是一趟排序,等一趟排序后,我们有一个值就放在了固定的位置

bc352aa97c514fc8aeda2f51c2da6da2.png 

假设是这样子的,我们第一趟已经拍好了,此时我们5就放在了固定的位置,接着我们就要排序0~4 和 6~9当然我们是先排序0~4的如果0~4排序好了以后就是这样

2c684d067e274a61a1564a4beadcbe94.png 

然后假设我们的2已经排序好了,然后我们继续排序

0~1    3~5  

就是这样

后面也都是这样,递归起来就是这样,所以我们如果想要使用栈来实现非递归那么我们要怎么做?

这里我就直接说了

我们可以先把数组的头和尾下标0和10给push到栈中,然后我们对这一段进行一趟排序,然后我们把这两个给pop掉,然后我们排序好之后返回了一个key

下面请看图片

就像这样

49d3683f46f349c095f1421be7f6db60.png

先push进去,然后对这一段数据进行一趟排序,假设我们排序好后就是5是key

当然我们是需要把0和10是要pop掉的,然后我们继续把 0和4push进去 在把6和10push进去

然后继续

看图片

6f535e31eb3c49d5adab995b8c9f7241.png

就像这样

e500b563255d40798488adf408aad7a0.png 

然后就是取栈顶的两个元素,对这两个元素间的数组进行排序,然后返回key为2

4620092026e746529bf301e7533ab6c1.png 

然后继续push就像这样,我们后面的也是这样子做的,下面直接看代码

97cfa2a547804606a5df6444e9a6d202.png 

就像这样,我们当然需要先有一个栈,然后就是对栈进行初始化等....

下面我们先把数组的头和尾push进去,如果栈不为空的话,那么就继续

等进去循环之后我们就记录push进去的头尾,然后对这段数组一趟排序,然后我们判断key是否需要push,如key-1都小于等于begin了,那么说明只剩下一个值了,或者是没有一个值了,所以我们就不需要push这段区间了,如果key+1大于等于end说明也没必须push了

就是这样,知道栈为空了,说明我们的排序也就结束了

 

 

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

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

相关文章

数字化和自动化的潮流:外贸企业如何应对?

当今世界正面临着数字化和自动化的浪潮,这些技术的应用正在深刻地改变着各个领域的生产、交易和管理方式。尤其在外贸行业,数字化和自动化的应用已成为一种趋势和必然。在本文中,我们将探讨数字化和自动化对外贸行业的影响和挑战,…

Windows环境下实现设计模式——解释器模式(JAVA版)

我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下Windows环境下如何编程实现解释器模式(设计模式)。 不知道大家有没有这样的感觉,看了一大堆编程和设计模式的书,却还是很难理解设计模式&#xff…

巧用千寻位置GNSS软件|CAD功能全解析

千寻位置GNSS软件中的CAD功能,用于已有 CAD的图形的导入和编辑,并且可以对 CAD图形已有线条进行线放样,在日常测绘工作中十分常见。下面向各位介绍CAD功能的使用技巧。点击【测量】->【CAD】,进入 CAD功能如图 5.3-1所示。以下…

三、线程状态【3/12】【多线程】

线程的状态3. 线程的状态3.1 观察线程的所有状态3.2 线程状态和状态转移的意义3.3 观察线程的状态和转移3. 线程的状态 3.1 观察线程的所有状态 线程的状态是一个枚举类型 Thread.State public class ThreadState {public static void main(String[] args) {for (Thread.State…

项目7:(aliyun)实现短信的发送和验证微服务和上传文件删除文件微服务

项目7:实现短信的发送和验证 1.对gulimall-common补充 2.短信验证的流程(aliyun的sms) 3.具体接口的编写(新建微服务service-sms) 4.上传和删除文件流程(aliyun的oss) 5.具体接口的编写&am…

区块链智能合约开发学习

最近正在肝区块链知识学习,入手学习智能合约的开发,由于网上资料实在是太少了,好不容易东拼西凑完成了智能合约的开发、编译、部署、web3js调用(网页页面)和web3j调用(java调用),赶紧…

Linux 内存回收,思维导图记录

最近天天跟内存斗智斗勇,整理下学习的记录 一些图片 参考 Tuning Linux Kernel Parameters For PostgreSQL Optimization PostgreSQL recommendations - Documentation for BMC Client Management 12.6 - BMC Documentation PostgreSQL load tuning on Red Hat E…

【vSphere | Python】vSphere Automation SDK for Python Ⅵ—— VM Guest Processes APIs

目录12. VM APIs12.1 VM Guest Processes APIsProcesses 进程Operations 操作(1)List Guest Processes(2)Get Guest Processes(3)Create Guest Processes(4)Delete Guest Processes参…

PaddleHub 更改模型默认下载位置

文章目录1.PaddleHub介绍2.PaddleHub安装3.PaddleHub使用中出现的问题4.更改PaddleHub模型的默认下载位置5. PaddleHub的简单使用1.PaddleHub介绍 PaddleHub 是基于 PaddlePaddle 开发的预训练模型管理工具,可以借助预训练模型更便捷地开展迁移学习工作&#xff0c…

docker内部执行nvidia-smi无任何显示的解决方法

docker内部执行nvidia-smi无任何显示的解决方法 贺志国 2023.4.11 今天在Docker内部编译程序,发现与CUDA相关的代码居然没有编译,于是在Docker内部执行Nvidia显卡驱动检测命令nvidia-smi,执行完毕后,无任何输出,也没…

计算机视觉面试题-网络结构相关问题总结-未完待续

VGG卷积核为什么取33 ? VGG使用33卷积核的优势是什么? Resnet 主要解决什么问题 为什么会有ResNet? 深度网络退化的原因 Resnet的针对网络退化提出的残差网络 Resnet网络结构 Resnet网络结构中如何实现的下采样 Resnet50网络结构Resnet特点 vgg16与 res…

Java并发篇二

ForkJoin 在JDK1.7,并行执行任务,提高效率,大数据量才会使用 特点:大任务拆分成小任务,工作窃取,里面维护的是双端队列 package com.kuang.forkjoin;import java.util.concurrent.RecursiveTask;/*** 如…

(PCB系列三)AD六层板布线经验累积

目录 1、布局: 2、创建电源类PWR 3、高速部分可以加屏蔽罩, 4、EMMC和NANDFLASH采取兼容放置(创建联合) 5、HDMI设计 6、就近原则摆放 7、AV端口 8、模拟信号(1字型或L型走线) 9、WIFI模块 10、局…

研究生,但是一直在摆烂学不进去

好的,我来为您创作一首歌曲,希望能够帮助您每天保持自律,专注学习。 《自律之歌》 第1节: 每天都要努力 学习不停歇 独自一人也要坚持 不放弃自己的梦想 读文献 写论文 我们不停探索 穷孩子的荣耀 就在不远处等候 合唱&#xf…

面试手撕算法题--下一个排列

前言 面试官描述这个题的时候,我就感觉似曾相识似乎做过,面完以后到leetcode找到原题恨不得给自个儿来一下子,的确,当时调api爽了,然后呢面试被拷打了啊,我想不起来这个api具体怎么解决这个题目的底层原理…

【非递归】手搓快速排序

欢迎来到 Claffic 的博客 💞💞💞 前言: 快速排序已经带大家实现过了,我们用到的方法是递归法,你知道吗,用循环也可以实现快速排序,来看看吧。 注: 这篇博客属于数据结构…

FE_CSS 基础选择器 字体属性 文本属性 综合案例

1 CSS 基础选择器 选择器分为基础选择器和复合选择器两个大类,基础选择器是由单个选择器组成的,基础选择器又包括:标签选择器、类选择器、id 选择器和通配符选择器。 1.1 标签选择器 标签名{属性1: 属性值1; 属性2: 属性值2; 属性3: 属性…

从0-1搭建交付型项目管理体系流程-- 项目启动篇【宝芝林5】

一. 目标及作用 本阶段主要的目标是签订合同及SOW工作说明书,其里程碑事件为甲乙双方完成合同及SOW工作说明书签字及盖章,以及召开项目启动会。 主要作用是明确项目甲乙双方的权利和义务,以及与甲方及其他实施团队共同制定项目章程&#xf…

有趣的Hack-A-Sat黑掉卫星挑战赛——被破坏的阿波罗计算机(解法一)

国家太空安全是国家安全在空间领域的表现。随着太空技术在政治、经济、军事、文化等各个领域的应用不断增加,太空已经成为国家赖以生存与发展的命脉之一,凝聚着巨大的国家利益,太空安全的重要性日益凸显[1]。而在信息化时代,太空安…

面试官:你做过什么有亮点的项目吗?

前言 面试中除了问常见的算法网络基础,和一些八股文手写体之外,经常出现的一个问题就是,你做过什么项目吗? 面试官其实是想看看你做过什么有亮点的项目, 其实大家日常做的项目都差不多,增删改查,登录注册&…