排序嘉年华———归并排序

本文详细介绍了归并操作,包括合并有序数组和链表的方法,以及递归和非递归形式的归并排序算法。通过实例代码展示了如何实现这些过程,并提供了测试示例。
摘要由CSDN通过智能技术生成

一.归并是什么?

相信朋友们应该做过一类题,合并两个有序数组,在链表里也有合并两个单链表的oj题,那我们稍微回顾一下

题目一:合并有序数组

普通思路:
1.定义一个第三方数组,用来临时归并排序
2.分别比较两个数组,小者先放进临时数组中
3.补充未排完的数组
4.将临时数组的值拷贝进返回数组nums1
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    int sum[m+n];
    int i=0,j=0,count=0;

    //比较取小尾插
    while(i<m&&j<n)
    {
        if(nums1[i]<=nums2[j])
        {
            sum[count++]=nums1[i++];
        }
        else
        {
            sum[count++]=nums2[j++];
        }
    }

    //补充
    while(i<m)
    {
       sum[count++]=nums1[i++];
    }
     while(j<n)
    {
       sum[count++]=nums2[j++];
    }

   memcpy(nums1,sum,sizeof(int)*(m+n));
}

题目二:合并有序链表

普通思路:
1.定义并维护指针head  tail
2.判断两种特殊情况
3.循环比较尾插
4.若有未链接的连结则直接尾插
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    struct ListNode *head=NULL, *tail=NULL;
    //两种特殊情况
    if (list1 == NULL)
        return list2;
    if (list2 == NULL)
        return list1;

    while (list1 && list2) {
        if (list1->val <= list2->val) {
            //初始状态判定
            if (tail == NULL)
                head = tail = list1;

            else {
                tail->next = list1;
                tail = list1;
            }
            if (list1)
                list1 = list1->next;

        } else {
            //初始状态判定
            if (tail == NULL)
                head = tail = list2;

            else {
                tail->next = list2;
                tail = list2;
            }
            if (list2)
                list2 = list2->next;
        }
    }
    //补充
    if(list1) tail->next=list1;
    else tail->next=list2;
    return head;
}

二.归并排序

字面意思,归并排序是通过将数据分别归并比较最终成为有序
在这里插入图片描述
建立一个临时数组,然后将数据两两归并放入临时数组,最终将有序数组拷贝回目标数组中

1.递归式归并

  • 首先动态开辟一个临时数组tmp
void Mergesort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
	}
	_Mergesort(a, 0, n - 1, tmp);
	
	free(tmp);
}
  • 然后编写子程序_Mergesort
void _Mergesort(int* a, int begin, int end, int* tmp)

四个参数,目标无序数组,目标起始下标,目标结束下标,已开辟的数组

  • 确定递归结束条件,归并的区间<=1时则可视为有序
if (begin >= end)
		return;
  • 分离出归并区间,取中间下标,递归式分离
//分离[begin1,end1][begin2,end2]
	int mid = (begin + end) / 2;
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	_Mergesort(a, begin1, end1, tmp);
	_Mergesort(a, begin2, end2, tmp);
  • 开始归并,这里的小细节是递归一次拷贝一组,边排边拷贝,不然可能导致数据丢失
//归并
	int i = begin;
	while (begin1<=end1&&begin2<=end2)
	{
		if (a[begin1] <= a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}

	memcpy(a+begin, tmp+begin, sizeof(int) * (end - begin + 1));

程序编写完成,测试一下

void test()
{
	int a[11] = { 9,6,7,3,1,5,7,10,0,0,1 };
	Mergesort(a, 11);
	for (size_t i = 0; i < 11; i++)
	{
		printf("%d ", a[i]);

	}
}

在这里插入图片描述

2.非递归式的归并排序

非递归思路是由分散的每个数据两两归并,然后成倍增加归并个体的数量,如下图
在这里插入图片描述

  • 先将组内数量设置为gap=1
int gap = 1;
	while (gap < n)
	{

	//...
		gap *= 2;
	}
  • 分理待归并数组
for (size_t i = 0; i < n ;i+=2*gap)
		{
			//分出两组区域
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			//...
		}
  • 如果是单纯end1或begin2越界出错则直接跳出,如果end2出错那就直接将end2的边界处理为n-1
// 边界的处理
			if (end1 >= n || begin2 >= n)
			{
				break;
			}

			if (end2 >= n)
			{
				end2 = n - 1;
			}
  • 然后开始基本环节归并并拷贝回目标数组
int j = begin1;
			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));
  • 最后释放临时数组
    free(tmp);
    测试一下:
void test()
{
	int a[11] = { 9,6,7,3,1,5,7,10,0,0,1 };
	MergeNRsort(a, 11);
	for (size_t i = 0; i < 11; i++)
	{
		printf("%d ", a[i]);

	}
}

在这里插入图片描述
两个完整代码已上传码云:递归和非递归归并排序
在这里插入图片描述
感谢大佬评论和建议

  • 42
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 34
    评论
意大利威尼斯是一个位于亚得里亚海的城市,被众多运河和桥梁所穿越,因其独特的地理位置和美丽的建筑而闻名于世。威尼斯也被称为“水城”或“浪漫之都”,其历史可以追溯到公元5世纪。 威尼斯的建筑风格独特,充满了浪漫和优雅的氛围。这座城市的建筑物大多建立在木桩上,因为城市被水所包围,没有用车辆行驶的道路。取而代之的是一系列运河和水道,人们需要乘坐船只或步行来穿越城市。 威尼斯对艺术和文化的贡献也是不可忽视的。文艺复兴时期,该城市是绘画、建筑和音乐的重要中心。许多著名的艺术家,如提香、蒂基安、巴拉托、威尔斯基和莫宁等,都在威尼斯创作了许多杰作。 除了艺术,威尼斯还以其独特的娱乐活动而著称。威尼斯嘉年华是世界上最古老、最盛大的狂欢节之一。每年,数以万计的游客和当地居民涌向威尼斯,穿着华丽的面具和服饰,参加各种游行、舞会和音乐会。 然而,威尼斯也面临着一些问题。城市的底层由于不断的垂直沉降而被淹没,建筑物也面临着沉降和腐蚀的风险。此外,游客数量的不断增加也给城市的环境和基础设施带来了压力。 总的来说,威尼斯是一个富有历史、文化和艺术底蕴的城市。尽管面临一些挑战,但它仍然是一个独特而迷人的旅游目的地,吸引着来自世界各地的游客。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

强sir的世界

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

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

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

打赏作者

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

抵扣说明:

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

余额充值