【八大排序(五)】快排进阶篇-挖坑法+前后指针法

news2025/1/11 5:02:12

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:八大排序专栏⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习排序知识
  🔝🔝


在这里插入图片描述

快排进阶篇

  • 1. 前情回顾
  • 2. 思路回顾
  • 3. 单趟快排挖坑法
  • 4. 挖坑法代码实现
  • 5. 单趟快排前后指针法
  • 6. 前后指针法代码实现
  • 7. 总结以及拓展

1. 前情回顾

我们上一章快排初阶 中介绍了
快排的思想和代码实现.
上一期单趟快排
介绍的是hoare版本
今天给大家分享挖坑法和前后指针法

注意:本章介绍的方法均用左边作为基准值

在这里插入图片描述


2. 思路回顾

基本思想: 🆙

  • 从待排序的数组中选取一个基准值.
    (我们把基准值记为key)

  • 再将数组分为两部分:
    1. 左子数组所有元素小于基准值
    2. 右子数组所有元素大于基准值

  • 左右子数组再选基准值重复这个过程

基准值key的选取: 🆙

采用三数取中法,详情见上一节快排初阶


怎么实现左右子序小于大于key: 🆙
有三种版本的方法:

  1. hoare版本(发明快排的人想出的方法)
  2. 挖坑版本(国内大佬想出的)
  3. 前后指针版本

3. 单趟快排挖坑法

基本思路: 🆙

  • 找到基准值,并记录下来
  • 将基准值的位置挖个坑位
  • 右边r先走,找比基准值小的
  • 找到后将这个值扔在坑中
  • 它本身变成新坑.以此类推
  • 当左边和右边相遇时
  • 将记录下来的key放在坑位

我们先定义一个无序数组:

int a[10]={6,1,2,7,9,3,4,5,10,8};

我们把最左边元素作为基准值

画图理解: 🆙

在这里插入图片描述

就这样右找到扔进坑位,左再找扔进坑位
直到左右l 和 r相遇.会发生这种情况:

在这里插入图片描述

走完单趟快排后,基准值6的
左子数组都小于它
右子数组都大于它

这说明: 🆙
6这个值已经来到了最终排好序时
它应该出现的位置

接下来我们只需要不断递归
基准值的左右子序就可以使
整个数组有序


4. 挖坑法代码实现

这里我直接省略掉三数取中函数:
GetMidIndex详情请看快排初阶

这是单趟快排: 🆙

//单趟快排(挖坑版本)
int Partion2(int* a, int left, int right)
{
	//三数取中--面对有序的情况不会栈溢出(key不会选到最大或者最小的数)
	int mini = GetMidIndex(a, left, right);
	swap(&a[left], &a[mini]);
	int key = a[left];
	int pit = left;//坑位起始位置是基准值的位置
	
	while (left < right)
	{
		//右边找小,放在左边的坑位中
		while (a[right] >= key && left < right)
		{
			right--;
		}
		a[pit] = a[right];//将找到的值扔进坑位
		pit = right;//自身变成新坑位
		
		//左边找大,放在右边的坑位中
		while (a[left] <= key && left < right)
		{
			left++;
		}
		a[pit] = a[left];//找到的值扔进坑位
		pit = left;//自己变成新坑位
	}
	a[pit] = key;//最终将相遇时的坑位给上最开始记录的key值
	return pit;//返回基准值(或者叫坑位)的位置,方便递归
}

这是递归调用函数: 🆙

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	int key = Partion2(a, left, right);
	QuickSort(a, left, key - 1);//递归左子序列
	QuickSort(a, key + 1, right);//递归右子序列
}

5. 单趟快排前后指针法

基本思路: 🆙

  • 定义两个指针cur和prev
  • cur指向第二个元素
  • prev指向cur前面的元素
  • c找比基准值小的值
  • 找到后停下,p向后走一格
  • 再交换c和p指向的值
  • 最后c走完数组后:
  • 交换key和prev的值

我们还是使用挖坑法的数组:

int a[10]={6,1,2,7,9,3,4,5,10,8};

我们把最左边元素作为基准值

画图理解: 🆙

在这里插入图片描述
和挖坑法一样:

走完单趟快排后,基准值6的
左子数组都小于它
右子数组都大于它

这说明: 🆙
6这个值已经来到了最终排好序时
它应该出现的位置

接下来我们只需要不断递归
基准值的左右子序就可以使
整个数组有序

并且前后指针法和挖坑法

得出的左右子数组顺序不一样

说明它们的底层思想是不同的


6. 前后指针法代码实现

单趟快排: 🆙

//单趟快排(前后指针版本)
int Partion3(int* a, int left, int right)
{
	//三数取中--面对有序的情况不会栈溢出(key不会选到最大或者最小的数)
	int mini = GetMidIndex(a, left, right);
	swap(&a[left], &a[mini]);
	int key = left;
	int prev = left;
	int cur = left + 1;
	while (cur <= right)
	{
		while (a[cur] >= a[key] && cur <= right)//cur指针找小于key的
		{
			++cur;
		}
		if (cur <= right)
		{
			swap(&a[++prev], &a[cur]);
			cur++;//交换完后,cur要再往后走一步
		}
	}
	swap(&a[key], &a[prev]);// 最后交换prev和key的值
	return prev;//返回基准值的位置,方便下次递归
}

递归函数: 🆙

//快速排序
void QuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	int key = Partion3(a, left, right);
	QuickSort(a, left, key - 1);
	QuickSort(a, key + 1, right);
}

7. 总结以及拓展

总结: 🆙
不管是hoare,挖坑还是指针版本
它们都有一个特性:
递归函数总体是不变的
改变的只是单趟快排实现的方法!

并且,不论是哪种方法实现单趟快排
算法效率也就是时间复杂度都是一样的

快排总归是抽象的
下面有一段快速排序过程
可以帮助你再深刻理解一下这个过程:

快速排序

拓展: 🆙

其实很多高效率的排序都是对
低效率的排序做的优化:

比如:

  • 快速排序实质上
    是对冒泡排序的一种改进

  • 堆排序实质上
    是对选择排序的一种改进

  • 希尔排序实质上
    是对插入排序的一种改进

排序在面试基本是必问的内容
往往面试官不会只问你快排的递归版
而是一层层剖析你的学识,问快排的递归
就会问快排的非递归.
所以非递归版本
将是你和其他面试者
拉开差距的关键一环!

在这里插入图片描述

学编程这一行只能说学无止境
一种方法可以延申出无数种解法


🔎 下期预告:快速排序终极篇 🔍

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

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

相关文章

chatgpt赋能python:Python排列组合:让编程更简单

Python排列组合&#xff1a;让编程更简单 Python是一种现代化的编程语言&#xff0c;同时也是一种强大的工具。在Python中&#xff0c;排列组合是极其重要的一种操作。在本篇文章中&#xff0c;我们将介绍Python中的排列组合&#xff0c;并探讨如何利用Python编程语言进行排列…

十.多线程

1、进程与线程 &#xff08;1&#xff09;操作系统与进程 1.程序&#xff1a;代码。 2.进程&#xff1a;程序的动态执行过程。 &#xff08;2&#xff09;进程与线程 线程&#xff1a;线程&#xff1a;是比进程更小的执行单位&#xff0c;一个进程在其执行过程中&#xff0…

chatgpt赋能python:Python中如何找到编程中的错误

Python中如何找到编程中的错误 Python是一种旨在提高开发者生产力的高级编程语言。由于其简洁性和可读性&#xff0c;它越来越成为开发者们的首选语言。然而&#xff0c;就像其他编程语言一样&#xff0c;Python编程中难免会有错误。本文将介绍一些有用的技巧和工具&#xff0…

STM32速成笔记—概述

文章目录 前言一、专栏简介二、前期准备三、编程规范以及程序架构简介1. 编程规范2. 程序架构 四、STM32F103ZET6简介 前言 本人技术菜鸟一枚&#xff0c;2022年大学毕业&#xff0c;大学加入老师实验室&#xff0c;参加过一些嵌入式相关的比赛&#xff0c;获得过2020年TI杯大学…

【利用AI让知识体系化】简要了解网络七层协议

文章目录 一、前言引言目的和意义 二、网络七层协议简介OSI参考模型七层协议分层结构和各层协议简介 三、物理层 - Layer 1物理层概述物理层的作用物理层标准和协议 四、数据链路层 - Layer 2数据链路层概述常见的协议 五、网络层 - Layer 3网络层概述网络层的作用IP地址的作用…

Nuxt.js:用 Vue.js 打造服务端渲染应用程序

文章目录 I. 简介Nuxt.js是什么Nuxt.js的历史和发展Nuxt.js的特点和优势1. 服务端渲染2. 自动生成路由3. 静态文件服务4. 异步数据加载5. 基于Webpack的构建系统6. 支持模块化的Vue组件7. 可定制的ESLint与StyleLint8. 支持PWA等高级功能 II. Nuxt.js基础Nuxt.js的安装和配置Nu…

ACL2023 | WebCPM:清华发布中文LFQA 数据集,探索搜索引擎和PLM大模型结合新范式

一、概述 title&#xff1a;WEBCPM: Interactive Web Search for Chinese Long-form Question Answering 论文地址&#xff1a;https://arxiv.org/abs/2305.06849 代码&#xff1a;https://github.com/thunlp/WebCPM 1.1 Motivation 开发一个类似于WebGPT一样的中文版本的…

如何保证数据库分布式事务的强一致性

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 针对分布式数据库&#xff0c;如何保证分布式事务的强一致性&#xff0c;是分布式数据库的关键。分布式事务的强一致性方案这里介绍两种&#xff0c;一种是GTM(global transaction manager),另一种是基于XA协议的两阶…

12道前端知识题目深入浅出下JavaScript

文章目录 1. 原型和原型链2. 作用域和闭包3. 高阶函数和函数式编程4. 异步编程和Promise、async/await5. 正则表达式6. 对象属性描述符和代理7. ES6新特性如模板字符串、解构赋值、箭头函数、let/const等8. 设计模式和架构模式设计模式架构模式 9. 性能优化技巧和调试技巧1. 性…

chatgpt赋能python:Python如何持续保存CSV文件

Python如何持续保存CSV文件 如果你需要不断更新数据并将其保存到CSV文件中&#xff0c;Python语言可以轻松完成这个任务。本文将介绍如何使用Python在代码执行的同时&#xff0c;将数据不断写入CSV文件中&#xff0c;实现持续保存的功能。 CSV文件是什么&#xff1f; CSV代表…

chatgpt赋能python:抓包是什么?

抓包是什么&#xff1f; 当我们在浏览器中访问一个网站时&#xff0c;我们的电脑会向网络服务器发送请求并接收响应。这个过程中&#xff0c;有一些工具可以让我们查看和分析这些请求和响应&#xff0c;其中最常用的就是“抓包”。 抓包就是指截获网络通信过程中的数据包并分…

chatgpt赋能python:Python怎么指定循环次数?

Python怎么指定循环次数&#xff1f; Python是一种广泛应用于编程领域的高级编程语言&#xff0c;它具有简单易学、代码可读性强、语言编写规范等诸多优点。其中&#xff0c;循环是Python语法中的重要一环&#xff0c;而如何指定循环次数则是其中一个重要的问题。 什么是循环…

Linux 检测通信路径上的PMTU(路径最大传输单元)

问题描述 终端设备向云端POST数据&#xff0c;数据量较小的没有问题&#xff0c;数据量大的必然出现丢包。网络很通畅&#xff0c;延迟较低。 分析 后来发现&#xff0c;终端到云端的通信路径上某个路由器节点的MTU小于终端的MTU&#xff0c;当终端发出的IP数据包长度大于该…

力扣题库刷题笔记4--寻找两个正序数组的中位数

1、题目如下&#xff1a; 2、个人Python代码实现如下&#xff1a; 代码如下&#xff1a; class Solution: def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: nums nums1 nums2 #合并数组 nums.sort() …

java【toString覆写】

笔试题 输出结果&#xff1a;D.func(),num0 解析&#xff1a; 继承的原则&#xff0c;先调用父类的无参构造&#xff0c;因此调用func()函数func() 此方法&#xff0c;new 的是 D 的对象&#xff0c;且被D所重写&#xff0c;触发动态绑定&#xff0c;直接调用D中的func()方法在…

Jupyter Notebook是什么及使用

一、什么是Jupyter Notebook Jupyter项目是一个非盈利的开源项目&#xff0c;源于2014年的python项目&#xff0c; Juptter Notebook&#xff0c;原名IPython Notbook&#xff0c;是IPython的加强网页版&#xff0c;一个开源web应用程序名字源自Julia、Python和R是一款程序员…

CRC校验(1):CRC原理、计算例子和最优多项式的选择

CRC(Cyclic Redundancy Check)&#xff0c;即循环冗余校验&#xff0c;它通过计算生成固定长度的校验码&#xff0c;用于验证数据在传输过程中是否发生了错误或损坏&#xff0c;从而确保数据的完整性。假设我们想把小写字母z发送出去。在Unicode中&#xff0c;z由数字0x7A表示&…

这有可能是国内最有趣的大学生知识交流社区了吧?

WRITE-BUG数字空间&#xff08;http://www.writebug.com&#xff09;内测 WRITE-BUG创建于2019年&#xff0c;创始团队主要来自于清华大学、中国人民大学等国内高校学生。运营至今&#xff0c;已累积100000注册用户&#xff0c;91%是18-24岁在校大学生&#xff0c;覆盖国内绝大…

前端vue基于秋云 ucharts echarts词云图 多重圆弧进度条 弧形进度条

前端vue基于秋云 ucharts echarts词云图 多重圆弧进度条 弧形进度条 进度条 弧形进度条 圆形进度条 词云图&#xff0c; 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id13029 效果图如下: #### 使用方法 使用方法 <!-- 关键字 --> &l…

java设计模式之:代理模式

文章目录 简介静态代理动态代理Cglib代理spring中AOP使用代理总结 简介 代理(Proxy)模式是一种结构型设计模式&#xff0c;提供了对目标对象另外的访问方式&#xff1b;即通过代理对象访问目标对象。 这样做的好处是&#xff1a;可以在目标对象实现的基础上&#xff0c;增强额…