当前位置: 首页 > article >正文

数据结构 ——— 快速排序算法的实现(hoare版本)

目录

快速排序的思想

单趟排序逻辑的实现

快速排序算法的实现


快速排序的思想

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

选出一个中间值 key,以升序举例,每一趟排序要保证 key 左边的元素比 key 小,key 右边的元素比 key 大,因为这样的话,key 停留的位置就是最后排好序的位置,就不用动了
然后比 key 小的区间再选出一个中间值 key,同样要保证 key 左边的元素比 key 小,key 右边的元素比 key 大;比 key 大的区间也是一样的操作
此操作类似于递归、分治的想法,直到最后 key 的左右两边只有一个数,且同样保证 key 比左大,比右小,那么数组就是升序了


单趟排序逻辑的实现

代码演示:

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

int PartSort_Hoare(int* a, int left, int right)
{
	int key = left;

	while (left < right)
	{
		// 先找右边比 key 小的元素的下标
		while (left < right && a[right] >= a[key])
			right--;

		// 再找左边比 key 大的元素的下标
		while (left < right && a[left] <= a[key])
			left++;

		// 交换 
		Swap(&a[left], &a[right]);
	}

	// 把 key 放在最终位置
	Swap(&a[key], &a[left]);

	return left;
}

代码解析:

通过以上每一趟排序的递归分治思想来看,left 和 right 并不是从数组的首尾开始递增递减的,而是每次从某一区间开始的

通常中间值的选取是最左边的值,那么 key 就是最左边值的下标
right 找比 key 小的元素,left 找比 key 大的元素
且要注意越界,因为在极端情况下,可能 key 的值小于或者大于任何一个元素
在 key 左边找到了比 key 大的值,在 key 右边找到了比 key 小的值,就进行交换
直到 left 和 right 相遇就停止,因为此时的 left 和right 都指向了同一个元素,没有可交换的

再把 key 放在最终位置,因为最开始 a[key] 是最左边的元素,那么当 while 循环走完时
left 和 right 同时指向的位置就是 a[key] 最终改放的位置

此时就完成了 a[key] 左边的元素比 a[key] 小,a[key] 右边的元素比 a[key] 大,且 a[key] 也放在了最终一个停留的位置

最后再把中间元素的下标 key 进行返回,为什么要返回下面会讲解到


快速排序算法的实现

代码演示:

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}

	int key = PartSort_Hoare(a, begin, end);

	// [begin,key-1] key [key+1,end]

	QuickSort(a, begin, key - 1);
	QuickSort(a, key + 1, end);
}

代码解析:

当 begin 等于 end 时,说明此区间只有一个元素了,那么就不用再递归
当 begin 大于 end 时,说明此区间不存在,同样也停止递归

以上就是递归结束的条件

先通过每一趟的算法函数对数组进行排序,排好后返回了中间元素的下标 key
此时数组 a[key] 左边的值小于等于 a[key],且 a[key] 右边的值大于等于 a[key]

再通过分治的思想进行递归,也就是 [begin,key-1] 这个区间再次排序,且 [key+1,end] 这一区间再次排序,同时配合递归的结束条件,最终完成对数组的排序

代码验证:


http://www.kler.cn/a/410840.html

相关文章:

  • rabbitmq 启动异常问题排查
  • 【通俗理解】隐变量的变分分布探索——从公式到应用
  • CSS —— 子绝父相
  • mmaction 、mmpose、rtmo和rtmpose
  • 价格分类(神经网络)
  • STM32F103C8T6实时时钟RTC
  • 贵州茅台[600519]行情数据接口
  • FFmpegFrameRecorder 切分视频文件时结束条件设置不当导致切分后的文件过短问题
  • 深度解析 Docker:重塑软件部署格局
  • Element UI 打包探索【1】
  • bridge-multicast-igmpsnooping
  • 第二十八章 TCP 客户端 服务器通信 - JOB命令示例
  • Python和R荧光分光光度法
  • 基于YOLOv8深度学习的农作物番茄成熟度检测系统研究与实现(PyQt5界面+数据集+训练代码)
  • jmeter基础06_(练习)常见的http请求
  • Reactor 模式的理论与实践
  • 即时通讯平台-音视频即时通讯平台就选WorkPlus
  • 虚拟苹果系统MacOS中新建自定义C++Dylib并用C++测试程序测试
  • QT 跨平台实现 SSDP通信 支持多网卡
  • 【ArcGISPro】使用AI提取要素-土地分类(sentinel2)
  • 用树莓派Pico控制8×8 LED点阵屏:深入解析C++核心知识与动态显示实现
  • 深度学习——3种常见的Transformer位置编码【sin/cos、基于频率的二维位置编码(2D Frequency Embeddings)、RoPE】
  • 突破内存限制:Mac Mini M2 服务器化实践指南
  • 提升软件测试报告的质量:Allure2中添加用例失败截图、日志、HTML块和视频的方法
  • 鸿蒙进阶篇-正则
  • 【linux】服务器加装硬盘后如何将其设置为独立硬盘使用