[ 数据结构 -- 手撕排序算法第五篇 ] 快速排序 非递归实现

手撕排序算法系列之第五篇:快速排序(下)

从本篇文章开始,我会介绍并分析常见的几种排序,大致包括直接插入排序,冒泡排序,希尔排序,选择排序,堆排序,快速排序,归并排序等。

大家可以点击此链接阅读其他排序算法:排序算法_大合集(data-structure_Sort)

快速排序的递归实现方法全部总结在这篇: 快速排序 <包含hoare法,挖坑法,前后指针法> 及其算法优化

这篇文章我们将一起讨论快速排序的非递归实现方法~ 

目录

1.快排非递归的实现思想

1.1具体步骤

1.2思想总结

2.快排非递归的代码实现

3.快排非递归的测试

4.时间复杂度 

4.1最好情况

4.2最坏情况

5.总结

1.快排非递归的实现思想

快排的非递归实现方法是利用了栈(栈 Stack)的特性,我们知道栈的特点是:先进去的数字后出来--所谓先进后出。那我们是怎么利用栈来搞快排的呢,其实现思想是和递归是一样的。

在快排的递归方法中,我们是将大区间划分划分划分成多个子区间,当子区间不能再划分时,递归中递的过程就结束了,这时候就要往回归。

非递归的思想适合递归是一样的。

1.1具体步骤

1、我们将一个区间的左右两边入栈,让right取栈顶元素(是我们后入的区间的右边),再删除栈顶的元素。同样,让left取先入但是后出的元素(区间的左边)。此时我们拿到了一个区间[left,right],我们对这个区间进行一次快速排序(使用hoare,挖坑,前后指针法均可)。

2、做一次之后我们有一个key值到了最终正确的地方,我们记录这个位置为keyi。此时大区间被划分为 [left,keyi-1] , keyi ,[keyi+1,right] 三部分。

3、我们在对这些小区间进行刚才相同的操作,将每个小区间的两边先后一次入栈,我们可以先入左边的区间[left,keyi-1],也可以先入右边的区间[keyi+1,right]。这次我们选择先入左边的区间[left,keyi-1]。

4、这样一次循环其实就结束了,我们只需要判断栈是否为空就可以判断排序是否完成。

可能文字说明比较抽象,我们选择更直观的画图来展现这个过程。

[ 数据结构 -- 手撕排序算法第五篇 ] 快速排序 非递归实现_第1张图片

左边的到底和右边一样,因此我们可以发现这样虽然不是递归但是也胜似递归,我们不再往下划分的条件就是区间元素小于等于1就不再往下划分。

1.2思想总结

其实通过上述的分析,我们发现非递归的思想就是一个循环,只不过我们总是取右边总是取右边,等右边全部有序了我们再往左边排序,划分小区间。

[ 数据结构 -- 手撕排序算法第五篇 ] 快速排序 非递归实现_第2张图片

其实之所以我们是先往右边再往左边这是由于我们的栈顶元素总是区间的右边的位置。

2.快排非递归的代码实现

我们发现如果用C语言来写非递归的话,首先要先实现一个栈~~~,一下写法不包括栈的实现,

栈的实现可以参考代码:栈的实现代码 (但是不可避免,要想使用必须这样)。

void QuickSortNonR(int* a, int begin, int end)
{
	ST st;
	StackInit(&st);
	StackPush(&st, begin);
	StackPush(&st, end);

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

		int keyi = PartSort3(a, left, right);
		// [left,keyi-1][keyi+1,right]
		if (left < keyi - 1)
		{
			StackPush(&st, left);
			StackPush(&st, keyi - 1);
		}

		if (keyi + 1 < right)
		{
			StackPush(&st, keyi + 1);
			StackPush(&st, right);
		}
	}
	StackDestory(&st);
}
//快速排序
void TestQuickSort()
{
	int a[] = { 6,1,2,7,9,3,4,5,10,8};
	QuickSortNonR(a, 0, sizeof(a) / sizeof(int) - 1);
	PrintArray(a, sizeof(a) / sizeof(int));
}
int main()
{
	//快速排序
	TestQuickSort();

	return 0;
}

3.快排非递归的测试

测试结果: 

[ 数据结构 -- 手撕排序算法第五篇 ] 快速排序 非递归实现_第3张图片

4.时间复杂度 

非递归时间复杂度依旧和递归一样,具体分析情况请参考上篇[ 数据结构 -- 手撕排序算法第五篇 ] 快速排序(上) -- 递归法

4.1最好情况

O(n*logN)

4.2最坏情况

O(n^2)

5.总结

本篇内容是对快速排序的补充。本篇主要实现了快排的非递归方法,使用栈来实现非递归思想也是非常的重要,一定要理解思想。

至此,快速排序的实现就完成了,我们大致分为递归和非递归两种方法,递归法又包含了俄中子方法。要想完全理解快排,独立实现快排,还需要习题的练习。

(本篇完)

你可能感兴趣的:(C语言,数据结构,排序算法,数据结构,排序算法,c语言)