快速排序三种思路详解!

news2024/11/15 18:40:36

一、快速排序的介绍

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。(其时间复杂度最优为N*logN,空间复杂度最优为lonN,这里就不予证明了!过程相当复杂!)

用一种通俗的话来讲快速排序其实就时设定一个界定值,然后分别开始遍历需要排序的元素,将小于该界定值和大于该界定值的放在其两侧,每次结束都能将该界定值放到其最终正确的位置!


二、快速排序的思想

快速排序其思想也是采用了分治的思想,将一个大问题转化为若干个小问题,然后逐个解决每个小问题,最终达到解决问题的目的!


三、快速排序的实现

由上面内容可以知道,若想实现快速排序,则可以先执行单个元素的排序,然后再进行递归处理解决整组数据的排序!因为快速排序是一种二叉树结构的交换排序,所以可以采用递归的方法将其解决!

 

下面来看一下如何实现单趟排序,让数据中一个元素位于其最终应处于的位置!

单趟排序的实现

注:本篇文章例子是以默认排升序,若要实现降序仅需要将循环条件改变一下即可!

法一:(霍尔思想)

其单趟排序的思想就是假定一个界定值,然后左右两边开始遍历,若要排升序,则左边找到的比界定值大的值就停下,右边找到比界定值小的就停下,然后交换两者的值,当左右两边相遇时,就结束循环,最后将相遇的位置的值与界定值交换位置即可完成本次界定值的最终位置的实现!

//注意:因为这是单趟排序,保证了界定值处于该数据最终所在的位置,所以该函数应返回本次界定值的位置,方便下次调用这个函数实现递归调用解决其另外界定值最终的位置!

画个图来形象的描述一下该过程是如何实现的吧!

代码如下:

int Hoare(int* a, int left,int right)
{
	int vali = left;
	while (left < right)
	{

		//若没有left<right这个限制条件,那么当从左边开始走的时候其对应的值一直小于a[vali]时,则会导致越界问题!
		//注意若选取vali在左边,那么从右边先走,因为从右边先走才能保证最后相遇的位置一定是小于vali的值,因为从右边找
		//的话是找比val小于或等于的值停下来!
		while (left < right && a[right] >= a[vali])
		{
			right--;
		}
		while (left < right && a[left] <= a[vali])
		{
			left++;
		}

		swap(&a[left], &a[right]);
	}

	//因为最后left和right相遇,所以只需将a[vali]与二者任意一个交换位置即可!
	swap(&a[left], &a[vali]);
	return left;
}

注意:(1)该函数的实现需要注意的是,必须保证里面的循环条件是left<right,因为假设当从左边开始时,其后面的值一直小于等于val时,则会导致left越界,进而导致程序错误!

(2)还需要注意一点的是,当选的界定值在左边时,那么必须从右边开始遍历,因为从右边先走可以保证最终左边相遇右边时,其遇到的右边一定是小于val的值,因为当最后左边和右边相遇时,还需要交换左边或右边的值与val的值,若交换的值大于val时,交换之后则没有排序成功,反之,若选的界定值在右边时,那么必须从左边开始遍历,原理同上!

法二(挖坑大法!)

原理如下:挖坑大法的原理就是选定一个界定值,将其保存起来,然后将其位置假设为一个坑,然后左右两边分别开始遍历,当左边找到比界定值大的值时,则将其数据填入坑中,坑的位置更新为新填入数据原来的位置,当右边位置找到比界定值小的值时,也将其数据填入坑中,坑的位置更新为新填入数据原来的位置!最后当左右相遇时,它们相遇一定是在坑中相遇,将原来界定值存放到坑中,此时界定值与其左右两边数据保持相对有序!图像如下:

注:这里假定坑位为左边第一个数据!那么就必须从右边开始先遍历,原因与法一相同!

 

 

代码如下:

int hole (int* a, int left, int right)
{
	int hole = left;
	int val = a[left];
	while (left < right)
	{
		//先从右边开始找比val小的值,找到后把坑填了,然后其位置就成为新的坑位!
		while (left < right && a[right] >= val)
		{
			right--;
		}
		a[hole ] = a[right];
		hole = right;

		while (left < right && a[left] <= val)
		{
			left++;
		}
		a[hole ] = a[left];
		hole = left;
	}

	a[hole ] = val;
	return left;
}

 法三:双指针

原理:定义两个快慢指针,当快指针指向的值小于界定值时,让慢指针向后走一步,然后交换快慢指针对应的值,不管如何快指针是都要向后走的,只有当快指针的值小于val时,慢指针才会向后走一步,然后与其值交换!最后当快指针走完整个数据循环结束!从其思想上面可以看出,当快慢指针之间的值都是比界定值大的数据,因为只有当指针指向的值小于界定值时,慢指针才会向后走,并与当前快指针指向的小于界定值的数据与前面的慢指针的值进行交换!

图像如下:

从图中可以看出,fast和slow之间的值都是大于界定值的!所以当fast找到比界定值小的数值后,进行slow++操作,然后交换二者位置,仍然可以保证 fast和slow之间的值还都是大于界定值!

代码如下:

int Dpointer(int* a, int left, int right)
{
	int slow = left;
	int fast = left + 1;
	int vali = left;
	while (fast<=right)
	{
		if (fast!=++slow && a[fast] < a[vali])//当slow++的位置和fast位置相同时就没必要进行交换了!
		{

			slow++;
			swap(&a[fast], &a[slow]);
		}
		fast++;
	}

	//注意一定要交换slow当前的值与原vali的值,然后将vali的位置重新赋值为slow的位置!
	swap(&a[slow], &a[vali]);
	vali = slow;
	return vali;
}

以上三种方法都是单趟的排序,因为快排是一种二叉树结构的交换排序方法,所以要想将所有元素进行排序,就可以采用递归的方法进行操作,从而完成整组数据的排序!

整组数据的排序实现!

代码如下:

void Qsort(int* a, int left, int right)
{
	//控制当区间不存在时,则跳出递归!
	if (left >= right)
	{
		return;
	}
	/*int vali = Hoare(a, left,right);*/

	//int vali = hig(a, left,right);
	int vali = Dpointer(a, left, right);
	Qsort(a, left, vali - 1);
	Qsort(a, vali+1, right);
}

当第一个排过序后,其第一个界定值就处于其最终存在的位置,所以可将界定值左边的元素再次进行一次排序,从而找到下一个界定值最终处于的位置,直至最后所要排序的区间不存在,排序即完成!

 

今日的快排分享到此为止,如有小伙伴还有不懂的地方欢迎在评论区留言提问哦! 

 

 

 

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

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

相关文章

电脑excel文件误删怎么恢复?分享6种有效方法

在日常办公中&#xff0c;电脑中存储的Excel文件可能会遭遇误删的意外情况&#xff0c;如何快速恢复误删的Excel文件成为许多人关注的热点。本文将介绍几种有效的方法&#xff0c;希望能够帮助您恢复误删的Excel文件。 方法1、从回收站恢复 检查电脑的回收站&#xff0c;如果E…

数字孪生是什么?工厂数字孪生实例分析

数字孪生是建筑物或城市等物理实体的 3D 模型&#xff0c;数字孪生具有实时、连续的数据&#xff0c;可实时更新其功能和流程&#xff0c;从而为工程师提供分析和优化生产流程的数据支撑。简单来说&#xff0c;数字孪生是物理实体的 3D 模型&#xff0c;3D 模型的动画由真实实体…

行业冠军NANK南卡再添新高度,打造百元级开放式蓝牙耳机新标杆!

​最近&#xff0c;国内最受欢迎的开放式耳机品牌NANK南卡推出了一款名为OE CC的产品&#xff0c;它以0感0压为卖点。不断根据用户的反馈进行优化&#xff0c;现如今这款耳机正式在各大平台上架销售。它采用了先进的技术&#xff0c;重新定义了百元级别开放式耳机的三个标准。这…

GD32-舵机的原理

GD32-舵机的原理 舵机的现一脉宽与舵机转动角度 旋转编码器的原理 顺时针&#xff1a;A的下降沿时&#xff0c;B处于高电平&#xff1b; 逆时针&#xff1a;A的下降沿时&#xff0c;B处于低电平&#xff1b; #ifndef _ENCODER_DRIVE_H #define _ENCODER_DRIVE_H#include &quo…

Matlab图像处理运算方法-非线性点运算

常见的非线性灰度变换为对数变换和幂次变换。 对数变换 对数变换的一般表达式为&#xff1a; tclog(1s) 其中c为尺度比例常数&#xff0c;s为输入图像灰度值&#xff0c;t为变换后的输出图像灰度值。在如下图所示的对数曲线上&#xff0c;函数…

node-red - 读写操作redis

node-red - 读写操作redis 一、前期准备二、node-red安装redis节点三、node-red操作使用redis节点3.1 redis-out节点 - 存储数据到redis3.2 redis-in节点 - 查询redis数据 附录附录1&#xff1a;redis -out节点示例代码附录2&#xff1a;redis -in节点示例代码 一、前期准备 安…

ensp-IPsec vpn配置

ensp-IPsec vpn配置 &#x1f4ce;IPsec VPN配置.docx&#x1f4ce;IPSec.zip

Windows和Linux卸载anaconda的完整解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

drag handle是什么意思?

Drag handle" 是一个术语&#xff0c;通常用于描述在用户界面&#xff08;如软件应用程序、网页等&#xff09;中用于拖拽或调整元素的小型图标、区域或手柄。它是一种交互式设计元素&#xff0c;用户可以通过拖拽它来改变界面上的元素的位置、大小或其他属性。 “Drag h…

数字孪生技术在3大行业的重点应用

数字孪生技术是利用模拟仿真技术将实体对象数字化的技术。它基于虚拟现实、人工智能和云计算等技术&#xff0c;能够创建与真实物体相同的数字模型&#xff0c;并通过实时监测和分析手段&#xff0c;提供关于该物体的全面数据&#xff0c;从而优化产品开发和生产过程。数字孪生…

熊猫:完整的初学者指南

pandas&#xff1a;完整的初学者指南 一、说明 在你的Python开发人员或数据科学之旅中&#xff0c;你可能已经多次遇到“熊猫”这个词&#xff0c;但仍然需要弄清楚它的作用。以及数据和熊猫之间的关系。所以让我向你解释一下。 根据最新估计&#xff0c;每天创建 328.77 亿 TB…

二分查找逻辑

目录 二分查找 查找逻辑 题目练习 题目描述 代码示例 总结 二分查找 二分查找是我们经常使用的一种算法&#xff0c;他的逻辑是 在升序或者降序且无重复元素的数组中&#xff0c;比较目标值和数组中间值的方法&#xff0c;每次缩小一半的搜索范围&#xff0c;相比遍历可…

Unity Alembic闪烁问题

最近在做项目时&#xff0c;发现Clo3D导出的服装abc动画&#xff0c;导入到Unity中后(已提前导入Alembic插件)&#xff0c;运行时屏幕会闪烁(变黑)。 经过几轮测试&#xff0c;发现是切线的问题。解决办法很简单。将abc文件上的Tangents属性值改为None即可。

一篇关于CPU的硬核知识分享

不管你玩硬件还是做软件&#xff0c;你的世界都少不了计算机最核心的 —— CPU。 01CPU是什么&#xff1f; CPU与计算机的关系就相当于大脑和人的关系&#xff0c;它是一种小型的计算机芯片&#xff0c;通常嵌入在电脑的主板上。 CPU的构建是通过在单个计算机芯片上放置数十亿…

app.js和页面.js 实现全局传参

实现全局传参的几个步骤&#xff1a;1. 在页面.js文件中 输入 const appgetApp() 2.便可以在页面中引用app.js中的globalData中的数据。 注意点&#xff1a;app.js中是使用的是this.globalData (调用自身的数据&#xff09; 页面.js中使用的是app.globalData&#xff08;引用ap…

Web 应用框架 Express 构建 RESTful API

Express框架 Express 是 Node.js 平台上最常用的 Web 应用框架之一&#xff0c;它简洁、灵活且易于使用。Express 提供了一组强大的功能和工具&#xff0c;可以帮助开发者快速构建 Web 应用程序和 RESTful API。 以下是 Express 框架的一些主要特点和功能&#xff1a; 轻量级…

c++11 标准模板(STL)(std::basic_istringstream)(五)

定义于头文件 <sstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_istringstream;(C11 前)template< class CharT, class Traits std::char_traits<CharT>, class Allocator std::allo…

国家管网:围绕招标全链路,聚焦提升招标管理数智化水平

“要深化供应链管理系统应用&#xff0c;推动全面应用电子招标平台开展工程建设项目招标&#xff0c;实现招标工作过程透明、效率提升和监管有力。” ——国家管网董事长 张伟 作为能源领域新的“国家队”&#xff0c;国家管网立足新变局应对新挑战&#xff0c;着力提升产业链…

vite按需引入elementPlus ,并自定义主题色

1. 首选无论是按需引入还是全引入都需要先安装elementPlus npm i element-plus 2. 按需引入elementPlus&#xff0c;可参照官网 a. 安装unplugin-vue-components 和 unplugin-auto-import npm install -D unplugin-vue-components unplugin-auto-import b. 配置vite.config.…

VScode使用SSH连接linux

1、官网下载和安装软件 https://code.visualstudio.com/Download 2、安装插件 单击左侧扩展选项&#xff0c;搜索插件安装 总共需要安装的插件如下所示 3、配置连接服务器的账号 安装完后会在左侧生成了远程连接的图标&#xff0c;单击此图标&#xff0c;然后选择设置图标…