快排补充(挖坑法,lomuto前后指针,非递归法)

挖坑法

挖坑法动态示意图

挖坑法方法分析

创建左右指针。⾸先从右向左找出⽐基准⼩的数据,找到后⽴即放⼊左边坑中,当前位置变为新 的"坑",然后从左向右找出⽐基准⼤的数据,找到后⽴即放⼊右边坑中,当前位置变为新的"坑",结 束循环后将最开始存储的分界值放⼊当前的"坑"中,返回当前"坑"下标(即分界值下标)。注意这里用的是lift<right此处的和快排的有区别,具体的情况需要根据实际情况进行区分。

源代码

int _QuickSort(int* arr, int left, int right)
{
	int hole = left;
	int base = arr[hole];
	while (left < right)
	{
		while (left < right && arr[right] > base)
		{
			right--;
		}
		arr[hole]=arr[right];
		hole = right;
		while (left < right && arr[left] < base)
		{
			left++;
		}
		arr[hole] = arr[left];
		hole = left;
	}
	//此时已经不满足,left<=right这时候把hole和关键值进行置换
	arr[hole] = base;
	return hole;
}

lomuto前后指针

创建前后指针,从左往右找⽐基准值⼩的进⾏交换,使得⼩的都排在基准值的左边。

前后指针方法分析

静态分析示意图

 思路:定义两个变量prev和cru这两个指针,用cur指向的位置与key的值进行对比,具体具有以下两者情况。

若arr[cru]<arr[key],pre向后移动,并把pre所指向的值与cru的值进行交换。

若arr[cru]>=arr[key],cru向继续后移动,当小于时再进行pre的后移动,并把pre所指向的值与cru的值进行交换。

前后指针方法的缺点

arr[cur]<arr[base]?

arr[cur]<=arr[base]?

 在这这两种情况下我们可以看出不论是小于等于还是小于,其实都会分成不均匀的两部分,这样会使后面递归调用的时间复杂较差。遇见相同元素的序列时使用前后指针效果较差,但是总体来说先后指针的思路和代码还是很好用的。

源代码

int _QuickSort(int* arr, int left, int right)
{
	int base = left;
	int prev = left;
	int cur = left + 1;
	while (cur<=right)
	{
		if( arr[cur]<arr[base]&& (++prev)!=cur)
		{
			swap(&arr[prev], &arr[cur]);
		}
		cur++;
	}
	swap(&arr[base], &arr[prev]);
	return prev;
}

非递归法

非递归法方法分析

示意图
  1. 找关键值的方法并未改变,可以使用(hoare,挖坑法,快慢指针)这三种方法。
  2. 根据基准值划分左右区间,左区间:[begin,keyi-1],右区间:[keyi+1,end]。两个注意点当区间的左侧大于右侧,或者左右两侧是一个相同的树就不在入栈了。
  3. 借助栈使用栈的循环模拟实现递归的功能。这里要注意入栈是先进后出,所以先right再入left。
  4. 循环到栈为空为止。

非递归的优点

  1. 避免栈溢出:递归调用函数可能会导致栈溢出,特别是在处理大规模数据时。使用非递归的方式可以避免这种情况的发生。

  2. 更容易实现:非递归的快速排序实现相对简单,不需要考虑递归调用的细节,也不需要处理递归栈的问题。

  3. 更容易优化:非递归的快速排序可以更容易地进行优化,例如使用迭代代替递归、使用栈来存储待处理的子数组等。

源代码

void swap(int* n, int* m)
{
	int temp = *n;
	*n = *m;
	*m = temp;
}
void QuickSortNonR(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);
		//[begin,end]---找基准值

		int prev = begin;
		int cur = begin + 1;
		int keyi = begin;

		while (cur <= end)
		{
			if (arr[cur] < arr[keyi] && ++prev != cur)
			{
				swap(&arr[cur], &arr[prev]);
			}
			cur++;
		}
		swap(&arr[keyi], &arr[prev]);

		keyi = prev;
		//根据基准值划分左右区间
		//左区间:[begin,keyi-1]
		//右区间:[keyi+1,end]
		//当左边大于右边或者值相同不入栈
		if (keyi + 1 < end)
		{
			StPush(&st, end);
			StPush(&st, keyi + 1);
		}
		if (keyi - 1 > begin)
		{
			StPush(&st, keyi - 1);
			StPush(&st, begin);
		}
	}

	StDestory(&st);
}

总结

以上就是咱们本次的内容,本次内容对快排进行了补充,从而更好的理解了非递归的方法。后续会继续补充,期待各位大佬支持一键三连(点赞,收藏,关注)。

  • 32
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值