数组——两个有序数组的合并

题目:有元素按照递增有序排列的两个数组arr,和brr,将brr的元素合并到arr中,且arr中的元素依然有序。arr的大小足够存放arr的有效元素和brr的有效元素。
例如:
arr[10] = {1,2,3};m=3//m为arr的有效数据个数
brr[7] = {1,2,3,4,5,6,7};n = 3//n为brr的数组长度(元素都有效)
合并后:arr[10] = {1,1,2,2,3,3,4,5,6,7};
主要讲述三种方法:
1.空间换时间(O(n),S(n))
2.在arr原数组操作,从前向后合并arr和brr数组(O(n^2),S(1))
3.在arr原数组操作,从后向前合并arr和brr数组(O(n),S(1))

一、空间换时间

思想:申请一个新空间大小,刚好够arr和brr数组有效数据存放。将arr和brr数据合并到新空间中,再将新空间数组赋值到arr中。

bool Merge_1(int* arr, int m, int* brr, int n, int arrlen)//m为arr有效数据个数,n为brr有效数据个数,arrlen为arr能够存储数据的个数
{
	if (m + n > arrlen) return false;//arr空间必须足够存放arr和brr的有效数据
	
	int* newdata = (int*)malloc(sizeof(int) * arrlen);
	if (newdata == NULL) return false;

	int i = 0;//arr下标
	int j = 0;//brr下标
	int k = 0;//newdata下标
	while (i < m && j < n)//依次将arr和brr中的较小的数据放入到newdata中
	{
		newdata[k++] = arr[i] < brr[j] ? arr[i++] : brr[j++];
	}
	while (i < m)//如果arr有剩余数据,将arr剩余数据放到newdata后面
	{
		newdata[k++] = arr[i++];
	}
	while (j < n)//如果brr有剩余数据,将brr剩余数据放到newdata后面
	{
		newdata[k++] = brr[j++];
	}
	memcpy(arr, newdata, sizeof(int)*arrlen);//将newdata的数据拷贝到arr里面

	delete newdata;//释放堆空间
	return true;
}

二、将arr和brr的元素从前向后合并到arr中

思想:i和j分别代表arr和brr待合并的数据的第一个数据下标
在这里插入图片描述
如果arr[i] <= brr[j],i就像后走,如果遇到arr[i] > brr[j]就将arr的i开始向后的数据向后移一位,将brr[j]赋值到arr[i]中,i++指向arr中待合并的数据的第一位,j++指向brr中下一个待合并的数据。如下图,arr[i] > brr[j]
在这里插入图片描述
如下图,将arr中的i开始的数据向后移一个单元格:
在这里插入图片描述
如下图,将brr[j]放到arr[i]中:
在这里插入图片描述
然后i和j都向后移一位,指向待合并的第一个元素(蓝色为已合并,红色为待合并),如下图:
在这里插入图片描述
重复上面步骤,代码如下:

//在原数组中操作,从两个数组的前面开始合并
bool one_move(int* arr, int len, int start,int last)//将下标为[start,last]的元素向后后移一个位置,不考虑last后的数据被覆盖的问题
{
	if (start < 0 || start > last || last >= len - 1) return false;
	for (int i = last; i >= start; i--)
	{
		arr[i + 1] = arr[i];
	}
	return true;
}

bool Merge_2(int* arr, int m, int* brr, int n, int arrlen)
{
	if (m + n > arrlen) return false;//arr空间必须足够存放arr和brr的有效数据
	
	int i = 0;
	int j = 0;
	while (i < m && j < n)
	{
		if (arr[i] > brr[j])//说明i的位置应该放brr[j],将arr的i开始的数据后移一个位置,i位置放brr[j]
		{
			if (one_move(arr, arrlen, i, m - 1) != true)//将arr的下标为[i,m-1]的数据后移一个位置
			{
				return false;
			}
			arr[i] = brr[j];//将brr[j]的数据放到arr[i]位置上
			i++;
			j++;
			m += 1;//arr有效数据加1
		}
		else//说明i的位置就应该还是arr[i]
		{
			i++;
		}
	}
	while (j < n)//说明arr的i走到了arr现有有效数据的最后一个位置的后面,将brr剩余的数据直接赋值到i开始向后的位置
	{
		arr[i++] = brr[j++];
	}
	return true;
}

三、从后向前合并数组arr和brr

思想:i为arr待合并数据的最后一个元素下标,j为brr待合并数据的最后一个元素下标,k为arr和brr元素合并到arr后,最后一个元素的下标,如下图:
在这里插入图片描述
如果arr[i] >= brr[j],将arr[i]赋值给arr[k],然后k和i都减减;
如果arr[i] < brr[j],将brr[j]赋值给arr[k],然后k和j都减减。
第一次的时候arr[i] == 3, brr[j] == 7,所以将brr[j]赋值给arr[k],然后k和j减减。
如下图:
在这里插入图片描述
然后再比较arr[i]和brr[j]值,重复 以上步骤,到最后:
在这里插入图片描述
上面这种情况属于arr元素都合并完了,brr还剩数据,将brr剩余数据都赋值给arr[k],然后k和j都减减就好了,直到brr合并完。还一种情况属于i没有走到头,但是j走到头了,说明brr合并完了,那么这个时候就合并完毕。
代码:

//在原数组中操作,从arr和brr的后面开始合并
bool Merge_3(int* arr, int m, int* brr, int n, int arrlen)
{
	if (m + n > arrlen) return false;//arr空间必须足够存放arr和brr的有效数据

	int i = m - 1;//arr下标
	int j = n - 1;//brr下标
	int k = m + n - 1;//合并后的最后一个元素下标
	while (j >= 0 && i >= 0)//arr元素先合并完或者brr元素先合并完,那么就退出
	{
		arr[k--] = arr[i] > brr[j] ? arr[i--] : brr[j--];
	}
	while (j >= 0)//如果brr还剩数据,说明arr合并完了,将brr剩余元素继续合并到arr前面就好了
	{
		arr[k--] = brr[j--];
	}
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孟小胖_H

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

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

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

打赏作者

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

抵扣说明:

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

余额充值