快速排序的实现(3种)

news2024/10/7 12:28:25

目录

  • 0.快速排序
  • 1.Hoare版本
    • 1.1基本思想
    • 1.2算法描述
    • 1.3画图解释
    • 1.4问题?
    • 1.5代码实现
  • 2.挖坑法
    • 2.1算法描述
    • 2.2画图解释
    • 2.3代码实现
  • 3.先后指针法
    • 3.1算法描述
    • 3.2画图解释
    • 3.3代码实现
  • 4.优化
    • 4.1优化方法
    • 4.2优化代码
  • 5.非递归实现快排
    • 5.1算法描述

0.快速排序

1.时间复杂度:O(N*logN)
稳定性:不稳定
整体综合性能和使用场景都比较好
空间复杂度:O(logN)

1.Hoare版本

1.1基本思想

通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

1.2算法描述

  • 从数列中选出一个元素作为基准(一般都是第一个元素)
  • 定义两个指针left,right。
  • right先走,找小,找到小就停下来;left后走,找大,找到大就停下来。然后交换left和right对应的值。
  • 重复上述操作,直到left和right相遇,停下来并交换相遇点的值和基准值。
  • 以基准值分成了两个区间,递归地重复上述操作。

1.3画图解释

第一遍:
right先走,找小;left后走,找大
left和right相遇时,交换相遇点和基准对应的值
达到了分区间作用;左区间 < 基准 ,右区间 > 基准

在这里插入图片描述

开始递归上述操作

在这里插入图片描述

1.4问题?

1.为什么要让right先走?如果left先走行不行?

让right先走最后可以满足比基准小的都在基准的左边,比基准大的都在基准的右边。
不行,如果left先走就不能满足上述条件
在这里插入图片描述

2.为什么left和right的相遇点对应的值一定小于等于基准?

left去遇见right:
right先走,找小,找到小就停下来;left后走,找大,找到大就停下来,两者对应的值发生交换;如果left没有找到与right发生相遇,所相遇点一定是小于基准的
right去遇见left:
right先走,找小,如果没有找到就一直走,直到和left相遇,此时相遇点所对应的值是小于基准的

1.5代码实现

// 快速排序hoare版本
void PartSort(int* a, int left, int right)
{
	if (left >= right)//表示该区间只有一个元素或者该区间不存在
		return;

	int begin = left;
	int end = right;
	int key = a[left];
	while (begin < end)
	{
		//先找小
		while (begin < end && a[end] > key)
			--end;
		//找大
		while (begin < end && a[begin] <= key)
			++begin;
		//交换begin和end位置的值
		swap(&a[begin], &a[end]);
	}
	//begin和end相遇
	swap(&a[begin], &a[left]);//swap(&a[begin,&key);两值会交换,但是系统并不知道key对应数组中第几个数据
	//[left,begin-1]  begin  [begin+1,right]
	PartSort12(a, left, begin - 1);
	PartSort12(a, begin + 1, right);
	
}

2.挖坑法

2.1算法描述

  • 把第一个数据存放在一个临时变量key中,形成坑位
  • right先走,找小,找到小就停下来
  • 将right所对应的值,放在坑位中,right形成新的坑位
  • left后走,找大,找到大就停下来
  • 将left所对应的值放在坑位中,left形成新的坑位
  • 当left和rihgt相遇时,两者都处在坑位位置,把临时变量key放到坑位中
  • 分区间递归

2.2画图解释

第一遍:
先将第一个数据放在一个临时变量(key)中形成坑位
right先走,找到小就放到坑位中去,right处形成新的坑位
left后走,找到大就放在坑位中去,left处形成新的坑位
分区间:左区间 < key ;右区间 > key

在这里插入图片描述

第二遍:递归重复上述操作

在这里插入图片描述

2.3代码实现

// 快速排序挖坑法
void PartSort2(int* a, int left, int right)
{
	//表示该区间只有一个元素或者该区间不存在
	if (left >= right)
		return;

	//创建一个临时变量存放第一个数据的值,形成坑位
	int key = a[left];
	int begin = left;
	int end = right;
	while (begin < end)
	{
		while (begin<end && a[end]>key)
			--end;
		a[begin] = a[end];
		while (begin < end && a[begin] <= key)
			++begin;
		a[end] = a[begin];
	}
	//begin和end相遇
	a[begin] = key;
	//[left,begin-1] begin [begin+1,right]
	PartSort2(a, left, begin - 1);
	PartSort2(a, begin+1, right);
}

3.先后指针法

3.1算法描述

  • 初始时,prev指到序列的开头,cur指到序列的下一个位置
  • 先判断cur位置对应的值和key(序列开头位置)的大小
  • 比key小 ++prev 将prev和cur所对应的值进行交换,然后++cur
  • 如果比key大,直接++cur
  • 当cur越界时,将key的值和prev的值进行交换

3.2画图解释

第一遍:prev指到序列的开头,cur指到序列的下一个位置
判断cur所对应的值与key的大小

在这里插入图片描述

递归重复上述操作

在这里插入图片描述

3.3代码实现

// 快速排序前后指针法
void PartSort3(int* a, int left, int right)
{
	//表示该区间只有一个数据或者该区间不存在
	if (left >= right)
		return;

	int begin = left;
	int end = right;
	int prev = begin;
	int cur = begin+1;
	int key = a[begin];
	while (cur <= end)
	{
		if (a[cur] < key)
		{
			++prev;
			swap(&a[cur], &a[prev]);
		}
		++cur;
	}
	//交换prev和key位置的值
	swap(&a[prev], &a[begin]);
	//[begin,prev-1] prev [prev+1,end]
	PartSort3(a, begin, prev - 1);
	PartSort3(a, prev+1,end);

}

4.优化

4.1优化方法

1.三数取中
2.小区间优化

1.为什么要进行三数取中?

当序列有序时,会加大快速排序所用的时间。分区间的时候,可能出现下面这种情况
在这里插入图片描述

int Mid(int* a, int left, int right)
{
	int mid = left + ((right - left) >> 1);
	if (a[left] > a[mid])
	{
		if (a[mid] > a[right])
			return mid;
		else if (a[left] > a[right])
			return right;
		else
			return left;
	}
	else//a[left]<a[mid]
	{
		if (a[right] > a[mid])
			return mid;
		else if (a[left] > a[right])
			return left;
		else
			return right;
	}
}

2.小区间优化

防止递归深度太深,栈溢出。同时可以减少所用时间。

4.2优化代码

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;

	
	//小区间优化
	//如果一个区间内的数据小于10个就进行小区间优化
	if ((right - left + 1) < 10)
	{
		InsertSort(a+left, right - left + 1);
	}
	else
	{
		//三数取中
		int mid = Mid(a, left, right);
		swap(&a[mid], &a[left]);

		int t = PartSort1(a, left, right);
		//[left,t-1] t [t+1,right]
		QuickSort(a, left, t - 1);
		QuickSort(a, t + 1, right);
	}
}

5.非递归实现快排

5.1算法描述

  • 建栈
  • 先将序列的left和right压入栈中
  • 再取出栈顶的left和right进行(挖坑法或前后指针法)
  • 再分区间把left和right压入栈中
  • 直到栈为空为止
    在这里插入图片描述

下面代码只有具体过程,没有与栈相关的代码

#include "Stack.h"
// 快速排序 非递归实现
void QuickSortNonR(int* a, int left, int right)
{
	ST st;
	StackInit(&st);
	//先压入right,再压入left
	StackPush(&st, right);
	StackPush(&st, left);

	while (!StackEmpty(&st))
	{
		int begin = StackGet(&st);
		StackPop(&st);
		int end = StackGet(&st);
		StackPop(&st);

		int keyi = PartSort1(a, begin, end);//分区间的点
			
		//[begin,keyi-1] keyi [keyi+1,end]
		//该区间不存在或者只有一个数据就不用压入栈中了
		if (begin < keyi - 1)
		{
			StackPush(&st,keyi - 1);
			StackPush(&st, begin);
		}
		if (keyi + 1 < end)
		{
			StackPush(&st,end);
			StackPush(&st, keyi + 1);
		}
	}
	StackDestory(&st);
}

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

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

相关文章

计算机系统基础知识(上)

目录 计算机系统的概述 计算机的硬件 处理器 存储器 总线 接口 外部设备 计算机的软件 操作系统 数据库 文件系统 计算机系统的概述 如图所示计算机系统分为软件和硬件&#xff1a;硬件包括&#xff1a;输入输出设备、存储器&#xff0c;处理器 软件则包括系统软件和…

代码随想录算法训练营第四十一天| 416. 分割等和子集

416. 分割等和子集 - 力扣&#xff08;LeetCode&#xff09; class Solution {public boolean canPartition(int[] nums) {int sum 0;for (int i0;i<nums.length;i){sum nums[i];}if(sum%2!0){return false;}int weight sum /2;// int[][] dp new int[nums.length][weig…

与亚马逊云科技深度合作,再获WAPP、ISV认证

上半年&#xff0c;VERYCLOUD睿鸿股份加入亚马逊云科技的WAPP&#xff08;Well-Architected Partner Programs&#xff09;和ISV加速计划&#xff08;ISV Accelerate Program&#xff09;&#xff0c;为客户带来更坚实优质的海外云服务。 Well-Architected 获得WAPP这项认证代表…

高考志愿填报:选好专业还是选好学校?

目录 引言 专业解析 工科类专业 文科类专业 医药类专业 商科类专业 名校效应分析 名校声誉的影响 教育资源和研究机会 学术氛围和创新能力 就业优势 好专业和好学校的权衡 职业目标的判断 行业需求的考量 教育质量的比较 结论 引言 2024年高考帷幕落下&#xff…

编程哲学——抽象

主要参考资料: App Image Format: https://docs.espressif.com/projects/esp-idf/zh_CN/release-v4.4/esp32s3/api-reference/system/app_image_format.html# 目录 简介抽象&#xff1a;从现实到模型类和对象&#xff1a;现实与模型的映射封装&#xff1a;隐藏复杂性继承&#…

▶《强化学习的数学原理》(2024春)_西湖大学赵世钰 Ch2 贝尔曼公式 【状态值、动作值】

PPT 截取有用信息。 课程网站做习题。总体 MOOC 过一遍 1、学堂在线 视频 习题 2、相应章节 过电子书 复习 GitHub界面链接 3、总体 MOOC 过一遍 还是跳过了一些 P38 学堂在线 课程页面链接 中国大学MOOC 课程页面链接 B 站 视频链接 PPT和书籍下载网址&#xff1a; 【github…

EDU学校漏洞sql注入挖掘记录

某搜索框 biaoti参数单引号报错 双引号正常 经过我的不断测试&#xff0c;’||exp(710)||’报错&#xff0c;exp函数就是执行e的多少次方&#xff0c;709不会报错&#xff0c;710会导致这个数太大报错 709正常,这里说明一下&#xff0c;因为这个数是小数所以返回200&#xff0c…

自学C语言-10

第10章 指针 指针是C语言的一个重要组成部分&#xff0c;是C语言的核心、精髓所在。用好指针&#xff0c;可以在C语言开发中起到事半功倍的效果。一方面&#xff0c;可以提高程序的编译效率、执行速度&#xff0c;以及动态存储分配&#xff1b;另一方面&#xff0c;可使程序更加…

MoonBit 周报 Vol.46:支持32位无符号整数!

MoonBit 更新 支持了 32 位无符号整数 let num 100U // 32位无符号整数的字面量需要后缀U在 wasm 后端导出返回值类型为 Unit 的函数时&#xff0c;之前导出函数的类型中会有 (result i32)&#xff0c;现在 MoonBit 编译器会自动生成一个没有返回值 wrapper 函数&#xff0c…

[leetcode]add-strings 字符串相加

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:string addStrings(string num1, string num2) {int i num1.length() - 1, j num2.length() - 1, add 0;string ans "";while (i > 0 || j > 0 || add ! 0) {int x i > 0 ? num1[i…

win10改远程桌面端口,Windows 10 修改远程桌面端口号的专业指南

在Windows 10系统中&#xff0c;远程桌面&#xff08;Remote Desktop&#xff09;功能允许用户从一台计算机远程访问和控制另一台计算机。为了增加远程连接的安全性&#xff0c;减少潜在的安全风险&#xff0c;修改默认的远程桌面端口号是一个常见的安全措施。以下是在Windows …

名侦探李先生第一话:谁是真正的凶手(只出现一次的数字相关题解(力扣)+位操作符回忆)

引子&#xff1a;我们在之前的案子中破解过基础的单身狗问题&#xff0c;那面对更有挑战的案子&#xff0c;且看李先生如何破局&#xff0c;那下凶手&#xff01; 复习&#xff1a; 1&#xff0c;位操作符&#xff1a; 正整数原&#xff0c;反&#xff0c;补码都相同 首位是…

长城与华为签署《HUAWEI HiCar 集成开发合作协议》,共创开发生态

近日&#xff0c;在2024年华为开发者大会上&#xff0c;长城汽车与华为签署《HUAWEI HiCar 集成开发合作协议》&#xff08;下称《协议》&#xff09;。这不仅标志着双方相关团队在技术方面的深度合作&#xff0c;更体现了两家公司共同提升未来智能出行体验的共同愿景。 而凭借…

SAPUI5基础知识8 - 模块(Module)的使用

1. 背景 在SAPUI5中&#xff0c;几乎所有东西都是一个模块&#xff08;例如&#xff1a;控件&#xff0c;控制器&#xff0c;组件等等&#xff09;&#xff0c;通过依赖管理&#xff0c;模块间可以相互调用。这样做的好处是&#xff0c;可以仅在需要时才去加载必需的模块&…

基于Openmv的追小球的云台

介绍 在这篇文章&#xff0c;我会先介绍需要用到且需要注意的函数&#xff0c;之后再给出整体代码 在追小球的云台中&#xff0c;比较重要的部分就是云台&#xff08;实质上就是舵机&#xff09;的控制以及对识别的色块位置进行处理得到相应信息后控制云台进行运动 1、舵机模…

基于 RGB的热成像无人机树冠数据集(目标检测)

亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 摘要&a…

Hightec编译器系列之高级调试技巧精华总结

Hightec编译器系列之高级调试技巧精华总结 小T为了便于大家理解&#xff0c;本文的思维导图大纲如下&#xff1a; 之前可能很多小伙伴没有使用过Hightec编译器&#xff0c;大家可以参考小T之前的文章《Hightec编译器系列之白嫖就是爽》可以下载一年试用版本。 小T使用过适配英…

vue中图谱关系插件relation-graph

vue中图谱关系插件relation-graph 一、效果图二、安装下载&#xff08;vue2.0版本的&#xff09;三、直接上代码 一、效果图 二、安装下载&#xff08;vue2.0版本的&#xff09; npm install --save relation-graph var foo bar;三、直接上代码 <template><div cla…

Notepad++插件 Hex-Edit

Nptepad有个Hex文件查看器&#xff0c;苦于每次打开文件需要手动开插件显示Hex&#xff0c;配置一下插件便可实现打开即调用 关联多个二进制文件&#xff0c;一打开就使用插件的方法&#xff0c;原来是使用空格分割&#xff01;&#xff01;&#xff01;

MySQL中的Redo-log是什么?有什么作用?

用来实现数据的恢复&#xff0c;数据被更新到缓冲区但没刷磁盘&#xff0c;然后MySQL宕机了&#xff0c;MySQL会通过日志恢复数据。 1.为什么需要Redo-log日志&#xff1f; MySQL绝大部分引擎都是基于磁盘存储数据的&#xff0c;每次读写数据都走磁盘&#xff0c;效率十分低下…