【初阶数据结构与算法】八大排序之非递归系列( 快排(使用栈或队列实现)、归并排序)

*【初阶数据结构与算法】八大排序之非递归系列( 快排(使用栈或队列实现)、归并排序)_第1张图片

文章目录

  • 一、非递归版快排
    • 1.使用栈实现非递归版快排
    • 2.使用队列实现非递归版快排
  • 二、非递归版归并排序
    • 1.非递归版归并排序的实现

一、非递归版快排

1.使用栈实现非递归版快排

   在学习非递归版快排前,建议大家先学习递归版的快排,否则非递归版的快排将很难理解,这里附上本人写的快排的博客解析:【初阶数据结构与算法】八大排序算法之交换排序(冒泡排序,快速排序—hoare、挖坑法、lomuto双指针3种版本)

   接下来我们来学习如何使用栈这个数据结构帮我们实现快排,首先我们都知道快排是通过递归实现的,那么问题来了,为什么栈就可以帮我们模拟递归的行为

   这就不得不提到递归的本质了,递归是通过函数自己对自己的调用,在内存的栈区开辟新的函数栈帧,执行同样的代码实现递归,此时我们要发现一个重点,就是递归的本质是通过在栈区开辟函数栈帧实现

   而栈区的压栈方式与我们数据结构中的压栈类似,所以我们才能通过栈这个数据结构来模拟递归调用的行为,只要理解到这一点,后面的内容将会好懂得多

   接着我们来正式实现非递归版的快排,首先我们需要一个栈作为辅助,可以将之前写过的栈导入到当前文件夹进行添加,栈在非递归快排中的任务就是存储下标

   因为我们递归划分数组不是真的把它们分开了,而是通过给定左右范围的下标来访问不同区域,以此达到划分数组的效果,所以快排递归最重要的信息是下标,只要我们能将下标保存并能够以类似于递归的方式使用,我们就可以不使用递归实现快排

   而栈就可以起到这样的效果,我们将指定数组序列的左右下标存入栈中,为了我们取出来是左右的顺序,我们在入栈时要将右下标先入栈,再入栈左下标,如下:

//非递归版快排
void NonRQuickSort1(int* arr, int left, int right)
{
   
	ST st;
	STInit(&st);
	STPush(&st, right);
	STPush(&st, left);

	STDestroy(&st);

   这样我们就可以保证我们取出对应下标时先取出左下标,再取出右下标,接着我们就创建一个循环,只要栈不为空,我们就进入循环取出对应的左右下标,简单进行一下判断,如果左右下标不符合要求就跳过后面的处理,如果左右下标没有问题就使用快排子函数对这段区间进行处理,最后返回处理好的基准值下标,如下:

while (!STEmpty(&st))
{
   
    //取出区间的下标
	int left = STTop(&st);
	STPop(&st);
	int right = STTop(&st);
	STPop(&st);
	//如果取出的下标不需要处理就直接使用continue跳过
	if (left >= right) continue;
	int keyi = _QuickSort(arr, left, right);
}

   接着我们就根据返回的基准值的下标对当前的区间进行划分,然后将这些划分后的下标入栈,要注意的是要从右往左将下标入栈,否则到时候取下标的时候可能左右下标相反的,如下:

//非递归版快排
void NonRQuickSort1(int* arr, int left, int right)
{
   
	ST st;
	STInit(&st);
	STPush(&st, right);
	STPush(&st, left);
	while (!STEmpty(&st))
	{
   
		int left = STTop(&st);
		STPop(&st);
		int right = STTop(&st);
		STPop(&st);

		if (left >= right) continue;
		int keyi = _QuickSort(arr, left, right);
		//[left, keyi - 1] [keyi + 1, right]
		STPush(&st, right);
		STPush(&st

你可能感兴趣的:(算法,数据结构,排序算法,c++,c语言,java,蓝桥杯)