快速排序02

这一篇文章主要讲解快速排序前后指针法和非递归实现,先把代码放到此处

前后指针

cpp 复制代码
void part2(int* arr, int* pbegin, int* pend,int keyi)
{
	int prev = *pbegin;
	int cur = *pbegin;
	while (cur <= *pend)
	{
		if (arr[cur] <  arr[keyi] && ++prev != cur)
		{
			Swap(&arr[prev], &arr[cur]);
		}
		cur++;

	}
	*pbegin = prev;
	

}

void QuickSort(int* arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	if (right - left < 10)
	{
		InsertSort(arr + left, right - left + 1);
		return;
	}
	int keyi = Mid_Search(arr, left, (left + right) / 2, right);
	Swap(&arr[keyi], &arr[left]);
	keyi = left;
	int begin = left;
	int end = right;
	//part1(arr, &begin, &end, keyi);
	part2(arr, &begin, &end, keyi);
	Swap(&arr[begin], &arr[keyi]);
	keyi = begin;
	QuickSort(arr, left, keyi - 1);
	QuickSort(arr, keyi + 1, right);
}

非递归

cpp 复制代码
void _QuickSortNon(int* arr, Stack* ps)
{
	while (!StackEmpty(ps))
	{
		int left = StackTop(ps);
		StackPop(ps);
		int right = StackTop(ps);
		StackPop(ps);

		if (left >= right)
		{
			return;
		}
		if (right - left < 10)
		{
			InsertSort(arr + left, right - left + 1);
			return;
		}
		int keyi = Mid_Search(arr, left, (left + right) / 2, right);
		Swap(&arr[keyi], &arr[left]);
		keyi = left;
		int begin = left;
		int end = right;
		//part1(arr, &begin, &end, keyi);
		part2(arr, &begin, &end, keyi);
		Swap(&arr[begin], &arr[keyi]);
		keyi = begin;
		//[left,keyi][keyi+1,right]
		if (keyi + 1 < right)
		{
			StackPush(ps, right);
			StackPush(ps, keyi + 1);
		}
		if (left < keyi)
		{
			StackPush(ps, keyi);
			StackPush(ps, left);
		}
		

	}

	


}
void QuickSortNon(int* arr, int left, int right)
{
	Stack st;
	StackInit(&st);
	StackPush(&st, right);
	StackPush(&st, left);
	_QuickSortNon(arr, &st);
	StackDestroy(&st);
}

前后指针法是另一种快速排序的实现方式,但是虽然换了一种方式,效率却相较之前没有提升,只是变得容易理解。

顾名思义前后指针法核心是前后指针,prev和cur两个指针,首先假设在不三数取中的情况下,把left当作keyi,prev和cur也初始化为left,cur判断自己值是否小于keyi对应的值,若小,则prev++,并交换prev与cur的对应值,反之cur++,prev不做处理,直到cur超出自己访问区间,将prev值与keyi交换,接着分治进行下一组排序。

相比于上一种写法,前后指针显然好理解一点。

接下来讲一讲非递归,为啥要有非递归?

假设数组有序,那我们快排逻辑(在不三数取中前提下)就会无休止的调用堆栈,导致栈溢出。

因为好比你用上一讲的快排方法,end找小于key的值怎么也找不到,所以一次递归就解决了第一个数,递归的深度相当高。

而非递归使用栈这数据结构,是在堆区中开辟空间,堆区的空间相当大,不太可能会发生溢出的情况。

然后是代码实现,首先需要栈这一个数据结构吧,然后我们之前递归的本质其实是分区间,找到一个相对中间的位置然后分而治之,左区间右区间循环往复,那又是什么划分了左右区间?其实就是我们传的下标,那递归的核心就是递归下标吧,同理,采用非递归我们也要存储区间下标,由于下标有左右两边,所以应该一次存储两个,一次弹出两个,直到栈为空就不再进行。

栈为啥会为空?其实也好理解,当我们出现区间就剩一个元素,或者区间一个元素都没有的情况,是不能入栈的,那么这次就相当于只出不进了,因此循环往复栈是会为空的。

相关推荐
careathers1 小时前
【数据结构】二叉树拓展
数据结构·算法
java_nnnn1 小时前
LeetCode刷题滑动窗口(长度最小的子数组)
算法·leetcode·职场和发展
@atweiwei1 小时前
训练 AI 大模型系列之 LoRA:不动模型本体,靠一条低秩旁路改专长(附完整手算算例)
人工智能·算法·ai·语言模型·rag
yi0111 小时前
DAY27: LeetCode 110. 平衡二叉树 | 在递归中判断是否平衡
人工智能·笔记·python·算法·leetcode·二叉树·递归
9624562 小时前
餐饮 SaaS 优惠券系统架构演进(七)营销定价引擎设计:活动、会员价、优惠券、买赠如何在同一 PriceQuote 中可解释地组合
java·运维·算法
xuxigifxfh2 小时前
牛客:HJ21 简单密码
java·开发语言·算法
qq_408606862 小时前
确界的倒数性质证明
学习·算法
小蒋观天下2 小时前
【安防AI工程实战二】AI摄像头帧率抖动根治:ISP曝光时序与AI推理时序冲突深度定位
人工智能·深度学习·算法·安全·机器学习·ai大模型
云和数据.ChenGuang2 小时前
trace 是RAG检索链路的**全链路追踪日志对象
人工智能·深度学习·算法·排序算法