数组al[0,mid-1]和al[mid,num-1]是各自有序的,对数组al[0,num-1]的两个子有序段进行merge,得到al[0,num-1]整体有序。要求空间复杂度为O(1)。

本文介绍了一种原地归并排序算法的实现方法,利用循环右移和元素交换技术,实现了两个相邻有序子数组的合并操作,最终使得整个数组有序,且额外空间复杂度为O(1)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目为:

数组al[0,mid-1]和al[mid,num-1]是各自有序的,对数组al[0,num-1]的两个子有序段进行merge,得到al[0,num-1]整体有序。要求空间复杂度为O(1)。

方法一:

1、两个有序段位A和B,A在前,B紧接在A后面,找到A的第一个大于B[0]的数A[i], A[0...i-1]相当于merge后的有效段,在B中找到第一个大于A[i]的数B[j],对数组A[i...j-1]循环右移j-k位,使A[i...j-1]数组的前面部分有序。
2、如此循环merge。
3、循环右移通过先子段反转再整体反转的方式进行,复杂度是O(L), L是需要循环移动的子段的长度。

再上代码吧

// 将有序数组a[begin...mid] 和 a[mid+1...end] 进行归并排序
void Merge(int *a , int begin , int end )
{
	int i , j , k;
	i = begin;
	j = 1 + ((begin + end)>>1);    //位运算的优先级比较低,外面需要加一个括号,刚开始忘记添加括号,导致错了很多次
	while(i <= end && j <= end && i<j)
	{
		while(i <= end && a[i] < a[j])
			i++;
		k = j;   //暂时保存指针j的位置
		while(j <= end && a[j] < a[i])
			j++;
		if(j > k)
			RotateRight(a , i , j-1 , j-k);   //数组a[i...j-1]循环右移j-k次
		i += (j-k+1);  //第一个指针往后移动,因为循环右移后,数组a[i....i+j-k]是有序的
	}
}

void Reverse(int *a , int begin , int end )   //反转
{
	for(; begin < end; begin++ , end--)
		swap(a[begin] , a[end]);
}
void RotateRight(int *a , int begin , int end , int k)    //循环右移
{
	int len = end - begin + 1;  //数组的长度
	k %= len;
	Reverse(a , begin , end - k);
	Reverse(a , end - k + 1 , end);
	Reverse(a , begin , end);
}
方法二:

主要思路是尽量不动前半部分子数组

假如i是指向前半部分的指针,j是指向后半部分的指针

有三种情况

1a[i]<a[j]时只需要把i向后移动一格

2a[i]==a[j]时,a[i+1]和a[j]交换,在后半部分子数组里并且把a[j}移动到按正常次序的位置

3a[i]>a[j]时,a[i]和a[j]交换,在后半部分子数组里并且把a[j}移动到按正常次序的位置

依次循环

直接上代码吧

void swap(int A[],int i,int j)
{
	int tmp=A[i];
	A[i]=A[j];
	A[j]=tmp;
}

int *mergeArray(int a[],int mid,int n)
{
	if(n<1)
		return NULL;
	if(mid>n-1)
		return NULL;
	int i=0,j=mid;
	while(i<mid&&j<n)
	{
		if(a[i]>a[j])
		{
			swap(a,i,j);
			int k=j+1;
			while(k<n)
			{
				if(a[k]<a[k-1])
					swap(a,k,k-1);
				else
					break;
				k++;
			}
		}
		else
		{
			if(a[i]==a[j])
			{
				++i;
				swap(a,i,j);
				int k=j+1;
				while(k<n)
				{
					if(a[k]<a[k-1])
						swap(a,k-1,k);
					else
						break;
					k++;
				}
			}
			i++;
		}
	}
	return a;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值