快速排序的非递归版本

目录

1.快速排序的递归版本

2.递归创建栈帧,储存了那些东西?

3.快速排序的非递归版本


每一次递归,都会在栈上开辟一块新的空间,如果递归的次数过多,在栈上开辟的空间过多,就会发生栈溢出,这是所有程序都要极力避免的,所以如果有使用递归实现的算法,都尽量改成非递归的算法,就能避免栈溢出.

# 1.快速排序的递归版本

快速排序有三种算法:霍尔法、挖坑法、双指针法

代码如下:

// 快速排序hoare版本
int PartSort1(int* a, int left, int right)
{
	int keyi = left;
	while (left < right)
	{
		while (a[right] >= a[keyi] && left < right)
		{
			right--;
		}
		while (a[left] <= a[keyi] && left < right)
		{
			left++;
		}
		swap(&a[left], &a[right]);
	}
	swap(&a[keyi], &a[left]);
	return left;
}
//挖坑法
int PartSort2(int* a, int left, int right)
{
	int keyi = left;
	int key = a[left];
	while (left < right)
	{
		while (a[right] >= key && left < right)
		{
			right--;
		}
		a[left] = a[right];
		while (a[left] <= key && left < right)
		{
			left++;
		}
		a[right] = a[left];
	}
	a[right] = key;
	return right;
}
// 快速排序前后指针法
int PartSort3(int* a, int left, int right)
{
	int key = a[left];
	int cur = left + 1;
	int prev = left;
	while (cur <= right)
	{
		if (a[cur] < key && ++prev!= cur)
		{
			swap(&a[prev], &a[cur]);
		}
		cur++;
	}
	swap(&a[left], &a[prev]);
	return prev;
}

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

	if (right - left < 200)
	{
		InsertSort(a+left, right-left+1);
		return;
	}

	// 随机选key
	int randi = left + (rand() % (right - left+1));
	swap(&a[left], &a[randi]);


	//三数取中
	//int midi = GetMidNumi(a, left, right);
	//swap(&a[midi], &a[left]);

	int keyi = PartSort2(a, left, right);

	// 递归
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi + 1, right);
}

# 2.递归创建栈帧,储存了那些东西?

我们看快速排序的函数类型:void QuickSort(int* a, int left, int right);可得知每一次创建栈帧都有三个变量:a,left和right.而a是一直不变的,所以如果考虑非递归版本,我们可以用一个数据结构把left和right存起来,这里我用栈结构存储所有的left和right;

# 3.快速排序的非递归版本

思路:首先把要排的left和right压栈,然后进入循环,弹出left和right,找到key,然后把左区间和右区间的left和right压栈,这里要注意,如果左区间或右区间只有一个元素了,该区间的left和right就不需要压栈了,因为就一个元素不需要排序了.下一个问题是什么时候结束循环?不难发现当栈为空的时候,就说明已经没有left到right的区间需要排序了,也就是说已经排好序了,所以进入循环的条件是栈不为空.以下是代码;

// 快速排序 非递归实现
void QuickSortNonR(int* a, int left, int right)
{
	Stack stack;
	StackInit(&stack);

	StackPush(&stack, right);
	StackPush(&stack, left);

	while (!StackEmpty(&stack))
	{
		left = StackTop(&stack);
		StackPop(&stack);
		right = StackTop(&stack);
		StackPop(&stack);

		if (right - left < 200)
		{
			InsertSort(a + left, right - left + 1);
			continue;
		}

		// 随机选key
		int randi = left + (rand() % (right - left + 1));
		swap(&a[left], &a[randi]);

		int keyi = PartSort2(a, left, right);

		if (keyi + 1 < right)
		{
			StackPush(&stack, right);
			StackPush(&stack, keyi + 1);
		}
		if (left < keyi - 1)
		{
			StackPush(&stack, keyi - 1);
			StackPush(&stack, left);
		}
	}

	StackDestroy(&stack);
}

以上就是所有内容,如有错误欢迎指出!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值