【初阶数据结构】打破递归束缚:掌握非递归版快速排序与归并排序

在这里插入图片描述

初阶数据结构相关知识点可以通过点击以下链接进行学习一起加油!
时间与空间复杂度的深度剖析深入解析顺序表:探索底层逻辑深入解析单链表:探索底层逻辑深入解析带头双向循环链表:探索底层逻辑深入解析栈:探索底层逻辑
深入解析队列:探索底层逻辑深入解析循环队列:探索底层逻辑树与二叉树:从零开始的奇幻之旅理解堆的特性与应用:深入探索完全二叉树的独特魅力深度解析七大常见排序:掌握底层逻辑与原理

本章将单独分享关于非递归实现快排和归并排序,可以帮助我们更好地理解递归和熟悉使用数据结构。

请添加图片描述
Alt

🌈个人主页:是店小二呀
🌈C语言笔记专栏:C语言笔记
🌈C++笔记专栏: C++笔记
🌈初阶数据结构笔记专栏: 初阶数据结构笔记

🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅
请添加图片描述

一、非递归实现快速排序

void QuickSortNonR(int* a, int begin, int end)
{
	ST s;
	STInit(&s);

	STPush(&s, end);
	STPush(&s, begin);

	while (!STEmpty(&s))
	{
		int left = STTOP(&s);//先拿出来
		STPop(&s);
		int right= STTOP(&s);//后拿出来
		STPop(&s);

        //单躺排序,一次调整,得到中间keyi值,划分填入
		int keyi = PartSort2(a, left, right);		
		//[left,keyi-1]keyi[keyi+1,right]
		
		if (left < keyi - 1)
		{
			STPush(&s, keyi - 1);
			STPush(&s, left);
		}
        
		if (keyi + 1 < right)
		{
			STPush(&s, right);
			STPush(&s, keyi+1);
		}

	}
	STDestroy(&s);
}

过程解析:非递归实现快速排序也是需要通过快速排序思想来走的,基本思想是以某数值为基准值,不断将待排序集合分割成两组子序列,采用前序遍历的方法根 左子树 右子树,对于递归的过程中我们知道左子树会演变为新的根,也会分为新根 新左子树 新右子树,然后我们将采用栈来模拟递归的过程,由于栈的特点是后进先出合前序遍历的特性。这里后进代表着左子树,新出代表着该左子树为根演变新左子树和新右子树的过程。然后这里需要范围去定义根(整体范围)、左子树(左边范围)、右子树(右边范围)。这里左子树会不断分为新的左子树和右子树,也意味着产生新的范围,一般来说先取左边(在上)再取右边(在下),对应着右边先压栈,左边再压栈。在这里插入图片描述

单躺排序结束会返回中间位置下标keyi帮整体划分为两部分,不断重复该过程。当条件不满足时,说明暂时不需要继续分为左子树和右子树,可能出现其他两种结果。第一种相等,说明只有一个数据;第二种大于。说明不存在数据,不需要压栈,等到栈为空结束排序。

二、非递归实现归并排序

在这里插入图片描述

由于快速排序采用是前序遍历满足栈相关数据结构的特性,然后归并排序属于后序排序因此不是通过使用栈区模拟非递归实现归并排序。如果采用栈去模拟实现非递归归并排序,由于归并排序不像快速排序不是出栈既排序,而是等到栈为空,开始归并排序,然而没有归并操作这种做法。

基本思路:整个序列分为以gap为子序列,结束条件为gap < n(gap = n - 1 表示归并最后一次),将两个有序子序列,比较大小尾插到新数组中,(子序列中只有一个数据时,默认是有序的)。对于两个有序子序归并在一起,形成一个新的有序子序列,当形成完新的子序列,复制到原数组中,不断重复该操作。

在这里插入图片描述

解决办法:对此应当设置变量gap为归并每组数据个数,首先gap设为1,以二的幂次方增长。

int begin1=i,end1=i+gap-1;

int begin2=i+gap,end2=i+2*gap-1;

[begin1,end1][begin2,end2]归并

注意点:这里gap是二的幂次方增长,对于两个子序列匹配时,规定数量是固定的,可能会出现越界访问,所以需要注意end1,begin2和end2的值。

在这里插入图片描述

对于end2只需要将修改为临界值就行,而对于end1和begin2则不参与进程。完成一趟for循环,需要拷贝到原数组中,这样子的话不参与进程的序列,将被随机值替代.

if (end1 >= n || begin2 >= n)  break;
if (end2 >= n)  end2 = n - 1;
void MergeSortNonR(int* a, int n)
{
    int* tmp = (int*)malloc(n * sizeof(int));
    if (tmp == NULL)
    {
        perror("malloc fail!!!");
        return;
    }
    int gap = 1;
    while (gap < n)
    {
        printf("gap:%2d->", gap);
        for (int i = 0; i < n; i += 2 * gap)//调正部分是跳过两组子序列,去到新的两组子序列中
        {
            int begin1 = i, end1 = i + gap - 1;
            int begin2 = i + gap, end2 = i + 2 * gap - 1;
            //printf("[%2d,%2d][%2d, %2d] ", begin1, end1, begin2, end2);
            if (end1 >= n || begin2 >= n)
            {
                break;
            }

            if (end2 >= n)
            {
                end2 = n - 1;
            }
            printf("[%2d,%2d][%2d, %2d] ", begin1, end1, begin2, end2);
			
            //上面是传值
            int j = begin1;
			
            //下面是插入,这里j下标很有讲究
            while (begin1 <= end1 && begin2 <= end2)
            {
                if (a[begin1] < a[begin2])
                {
                    tmp[j++] = a[begin1++];
                }
                else
                {
                    tmp[j++] = a[begin2++];
                }
            }//还有部分数据没有放入新数组中
            while (begin1 <= end1)
            {
                tmp[j++] = a[begin1++];
            }
            while (begin2 <= end2)
            {
                tmp[j++] = a[begin2++];
            }
            memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));//可能是右边归并
        }
        printf("\n");
        gap *= 2;
    }	
    free(tmp);
}

以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二初阶数据结构笔记,希望对你在学习初阶数据结构中有所帮助!
在这里插入图片描述

  • 67
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 70
    评论
评论 70
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是店小二呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值