排序——快速排序

目录

思想

演示

代码实现

解释

优化

三数取中

小区间优化

补充

挖坑法

双指针法

非递归实现


思想

     快速排序是一种二叉树结构的交换排序方法。

     基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

演示

     一般把序列的第一个元素认为基准值。定义两个变量一个是序列最右边一个是最左边(变量均为下标)。

09ad479c52504f9b9387557660440f67.png

     先让end走遇到比基准值小的停下来,然后让begin走遇到比基准值大的停下来,之后让它们交换位置。一直重复操作直至它们相遇。

d27f511fecf04b008ab32f3b232401f1.png

b93006cbb40f40c897e4163fe503105e.png

1e23283adf684531a2b28407657a8e81.png

d3633959a1c54bc19c5186675cd505fe.png1f609660eb054e3eaf83e280e10a886d.jpg

当它们相遇时,该位置的值一定小于基准值(在后面的解释中会有说明)。让该位置的值与基准值交换。

e928876ecbf241229a8a2d1d30d03031.png

     以上是一遍排序,还要继续排序下图的浅绿色序列和亮绿色序列,操作是和这次一样的只是范围不一样。在排完之后会继续再分用递归解决即可。

4c5f89cfdd964958aabbfc59a3e56539.png

     大概流程图如下 :

0d2a8dfee2bc4a5aac6f6aa0fe720cf9.png

     大家不能只看我画的图,也要自己画画图感受感受。

代码实现

//快速排序
void QuickSort(int* arr, int left, int right)
{
	if (left >= right)
		return;

	int keyi = left;
	int begin = left, end = right;
	while (begin < end)
	{
		while (begin < end && arr[end] >= arr[keyi])
			end--;
		while (begin < end && arr[begin] <= arr[keyi])
			begin++;

		Swap(&arr[begin], &arr[end]);
	}

	Swap(&arr[keyi], &arr[end]);

	keyi = begin;
	QuickSort(arr, left, keyi - 1);
	QuickSort(arr, keyi + 1, right);
}

      Swap函数是交换两个数。

void Swap(int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

解释

  • end遇到begin:
  1. begin没移动:那就是自己给自己交换一下位置。
  2. begin移动了:begin经历了交换它下面的值一定小于基准值。
  • begin遇到end:因为end先走,end停下的位置一定小于基准值。

     这也就解释了为什么要让end先走,如果要让begin先走那可能就不会当它们相遇时该位置的值一定小于基准值。

优化

三数取中

     快速排序的理想时间复杂度是O(NlogN),理想情况每次左右序列的长度相同时存在。如果该序列是有序或接近有序那时间复杂度就是O(N^2)如下图。这样快速排序的效率就会大打折扣。为了避免这种情况有人提出了三数取中。

c43a33fad8c54bd9b68e473bd572101a.png

     三数取中就是在序列中拿首元素,序列正中间的元素,尾元素这三个元素中挑一个中间元素来当基准值。这样做尽量保证每次的左右序列的长度相同,让它向理想情况靠近。

     当选出来时让该位置与序列首元素交换位置这么做是保证我们之前的逻辑。

//三位取中
int GetMidi(int* arr, int left, int right)
{
	int midi = (left + right) / 2;
	if (arr[left] < arr[midi])
	{
		if (arr[midi] < arr[right])
		{
			return midi;
		}
		else if (arr[left] > arr[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else
	{
		if (arr[midi] > arr[right])
		{
			return midi;
		}
		else if (arr[left] > arr[right])
		{
			return right;
		}
		else
		{
			return left;
		}

	}
}

小区间优化

     在上面提到过快速排序是一种二叉树结构的交换排序方法。

     它是一个二叉树结构,根据二叉树特点可知最后一层开辟的空间会约占全部的50%,它的上一层约占到25%。如果数据很多那么递归调用的深度就会很深有可能造成——栈溢出。

     最后的一两层里面包含的数据并不是很多,所以我们可以写一个判断,到特定的范围内用插入排序的方式来排序(这里我写的是当数据量小于10时),这样它的深度会变小很多。

补充

挖坑法

     这是针对排一遍方法的改进下面的双指针法也是一个道理。

     将第一个数据存在一个临时变量key中,从而形成一个坑位。让end先走当遇到比key小的数据时把end位置的值放入坑中,end位置就会形成一个坑。然后让begin走遇到比key大的就把它放入坑中。一直重复操作直至它们相遇。

4737ce536ba6427ab66de936fe6880fb.png

     最后它们相遇时把key放入它们相遇位置即可。

c8f74b82d5d24ce18febf24864dd5d15.png

双指针法

     先定义两个变量一个指向序列的首元素(prev),一个指向首元素的下一位(cur)。

     如果cur对应的值大于key(序列首元素),那就让cur独自向后走。如果小于key,让prev向后走然后让cur和prev交换位置如果cur等于prev那就不需要交换位置(下图是一部分移动过程)。

c8ba9d5565414bc8aa474127e2fb80a9.png

     当cur走出序列后,让prev与key进行交换。

     prev是在cur对应的值小于key的情况下才走固prev对应的值一定小于key。

非递归实现

     快速排序的非递归实现是基于栈实现的。在递归中只有范围在不断改变,所以我们只需要在栈里存放范围即可。

     要先在栈里存入序列的最左边的下标和最右边的下标。在排序时拿出下标。排完后再向栈中压入由它分出来的两个序列的左右下标。

//快速排序
void QuickSort(int* arr, int left, int right)
{
	ST st;
	STInit(&st);//初始化栈
	STPush(&st, right);//入栈
	STPush(&st, left);

	while (!STEmpty(&st))//判断栈是否为空
	{
		int begin = STTop(&st);//取出栈顶元素
		STPop(&st);//出栈
		int end = STTop(&st);
		STPop(&st);

		int keyi = begin;
		int prev = begin, cur = prev + 1;
		while (cur <= right)
		{
			if (arr[cur] < arr[keyi] && ++prev != cur)
			{
				Swap(&arr[prev], &arr[cur]);
			}
			cur++;
		}
		Swap(&arr[keyi], &arr[prev]);

		if (prev + 1 < end)//当只有一个数据时没必要入栈了
		{
			STPush(&st, end);
			STPush(&st, prev + 1);
		}
		if (begin < prev - 1)
		{
			STPush(&st, prev - 1);
			STPush(&st, begin);
		}
	}

	STDestroy(&st);//销毁栈
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[渗透测试学习] SolarLab-HackTheBox

SolarLab-HackTheBox 信息搜集 nmap扫描端口 nmap -sV -v 10.10.11.16扫描结果如下 PORT STATE SERVICE VERSION 80/tcp open http nginx 1.24.0 135/tcp open msrpc Microsoft Windows RPC 139/tcp open netbios-ssn Microsoft Windows n…

【漏洞复现】致远互联FE协作办公平台 ncsubjass SQL注入

0x01 产品简介 致远互联FE协作办公平台是一款为企业提供全方位协同办公解决方案的产品。它集成了多个功能模块&#xff0c;旨在帮助企业实现高效的团队协作、信息共享和文档管理。 0x02 漏洞概述 致远互联FE协作办公平台 ncsubjass.jsp接口处存在SQL注入漏洞,未经身份验证的…

1.4k star 项目 CMakeTutorial 阅读和点评

1.4k star 项目 CMakeTutorial 阅读和点评 文章目录 1.4k star 项目 CMakeTutorial 阅读和点评0. 概要1. CUDA 目录2. FindPackage 目录3. Installation 目录4. PackageManage 目录5. PythonExtension 目录6. ImportExternalProject 目录总结 0. 概要 在 github 搜索关键字 CM…

ORA-12560: TNS:协议适配器错误

项目场景&#xff1a; 由于最近一直没有连接oracle&#xff0c;然后之前windows也是正常可以启动oracle&#xff0c;正常连接。无论是SQL Developer还是SQL PLUS命令&#xff0c;都能正常连接和操作。 问题描述 这两天刚好用SQL Developer工具连接&#xff0c;然后报错&#…

vue中通过自定义指令实现一个可拖拽,缩放的弹窗

效果 功能描述 按住头部可拖拽鼠标放到边框&#xff0c;可缩放多层重叠丰富的插槽&#xff0c;易于扩展 示例 指令代码 export const dragDialog {inserted: function (el, { value, minWidth 400, minHeight 200 }) {// 让弹窗居中let dialogHeight el.clientHeight ?…

和鲸101计划:以神经计算建模培训,助力北大学术人才培养

探索与求知&#xff0c;培养与传承。 让青年人更早地触摸到科学研究的前沿&#xff0c;便能吸引更多人才投身于学科建设。 11月4日&#xff0c;由北京大学信息处理实验室开展进行&#xff0c;北京大学心理与认知科学学院院长吴思教授及课题组成员授课的第二届神经计算建模及编…

C#心跳机制客户端

窗体&#xff08;richTextBox右显示聊天&#xff09; 步骤 点击链接按钮 tcpclient客户端步骤 1创建客户端对象 2连接服务器connect 3创建网络基础流发消息 .write发消息 4 创建网络基础流接消息 .read接消息 5 断开连接…

Spring注解----------@Deprecated

情景&#xff1a; 在我们开发过程中&#xff0c;有时候会遇到我们需要将几个类中的方法集中到一个类中&#xff0c;但是我们又不希望把我们的原来的类删掉&#xff08;就是单纯的不想删除&#xff0c;都是我写的代码我不想杀死我的结晶&#xff0c;不能说我写的是shi&#xff…

【C语言】--- 常见调试信息预处理器宏

在编程的艺术世界里&#xff0c;代码和灵感需要寻找到最佳的交融点&#xff0c;才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里&#xff0c;我们将共同追寻这种完美结合&#xff0c;为未来的世界留下属于我们的独特印记。 【C语言】--- 常见调试信息预处理器宏 开…

Multisim仿真之万用表、安捷伦万用表、信号发生器操作方法

1、XMM是安捷伦示波器 如下图所示&#xff0c;实物安捷伦的外围3个插孔对应于 XMM图标示波器的右侧3个引脚&#xff0c;上下一一对应 2、函数信号发生器XFG 如下图所示&#xff0c;COM就是GND&#xff0c;正负的意思就是相对于GND而言&#xff0c;有正负电压&#xff1b; 3、…

vivado PIP or SITE_PIP、PKGPIN_BYTEGROUP

PIP是Xilinx部件上用于路由连接或网络的设备对象。PIP 称为ARC的连接多路复用器可以编程为将一根电线连接到 另一个&#xff0c;从而将节点连接在一起&#xff0c;以形成中特定NET所需的路由 设计。 SITE_PIP&#xff0c;也称为路由BEL&#xff0c;是SITE内部的连接多路复用器&…

JavaFX按钮

当用户单击按钮时&#xff0c;JavaFX Button类可以触发事件。Button类扩展了Labeled类&#xff0c;可以显示文本&#xff0c;图像或两者都可以。 以下代码显示了如何向Button添加单击操作侦听器。 import javafx.application.Application; import javafx.event.ActionEvent; im…

【信息学奥赛】CSP-J/S初赛03 计算机网络与编程语言分类

第1节 计算机网络基础 1.1 网络的定义 所谓计算机网络&#xff0c;就是利用通信线路和设备&#xff0c;把分布在不同地理位置上的多台计算机连 接起来。计算机网络是现代通信技术与计算机技术相结合的产物。 网络中计算机与计算机之间的通信依靠协议进行。协议是计算机收、发…

Postman文件数据导入导出

前言 不同的接口测试工具如Postman、Apipost、Apifox创建的接口文档都是互通的&#xff0c;都可以互相兼容使用。我们就不需要在3个不同测试工具都去创建&#xff0c;只要在一个工具上创建&#xff0c;想要在其他接口测试工具上使用就运用导入和导出功能即可。 Postman、Apip…

2024.6.18 作业 xyt

今日作业&#xff1a; 1. 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果…

【shell脚本速成】for 嵌套和和 if 高级用法

文章目录 一、for嵌套二、for与数组三、if高级用法3.1、条件符号使用双圆括号&#xff0c;可以在条件中植入数学表达式 if (())3.2、使用双方括号,可以在条件中使用通配符 四、简写if五、与文件存在与否的判断六、课后练习 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &…

智能网站管理系统

智能网站管理系统&#xff0c;即智能化的网站管理工具&#xff0c;是为了提高网站管理效率和简化操作流程而开发的一种软件系统。它集合了各种先进的技术和功能&#xff0c;为网站管理员提供了一套强大而可靠的解决方案。 智能网站管理系统的核心功能是网站内容管理。传统的网站…

MySQL 基本语法讲解及示例(上)

第一节&#xff1a;MySQL的基本操作 1. 创建数据库 在 MySQL 中&#xff0c;创建数据库的步骤如下&#xff1a; 命令行操作 打开 MySQL 命令行客户端或连接到 MySQL 服务器。 输入以下命令创建一个数据库&#xff1a; CREATE DATABASE database_name;例如&#xff0c;创建一…

(资料收藏)王阳明传《知行合一》共74讲,王阳明知行合一音频讲解资料

今天给大家带来的不是软件&#xff0c;而是一份精神食粮——《知行合一》的教程福利。这可不是一般的教程&#xff0c;它关乎心灵&#xff0c;关乎智慧&#xff0c;关乎我们如何在纷繁复杂的世界中找到自己的位置。 咱们得聊聊王阳明&#xff0c;这位明代的大儒&#xff0c;他…

看完这篇文章你才能了解什么是大模型

引言 近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术迅速崛起&#xff0c;成为全球科技领域的热门话题。大模型&#xff08;Large Language Model&#xff09;技术以其庞大的参数和复杂的结构&#xff0c;为AI提供了强大的计算和学习能力&#xff0c;推动着AI技术…