PAT (Basic Level) 1035 插入与归并(模拟)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_45458915/article/details/102699173

题目链接:点击查看

题目大意:给出两列数字,问第二列数是由第一列数怎样排序得到的,题目保证答案唯一,并且只有归并排序或插入排序两种选择

题目分析:因为一开始不太了解归并排序和插入排序的特点,所以有点无从下手,去网上看了一下各自的特点后,就有了模拟的大致方向了,先在这里挂一下两种排序中间过程的特点:(针对这个题目而言)

  1. 插入排序: 前面的一段连续序列有序,后面剩下的序列与原序列一一对应
  2. 归并排序:设当前归并长度为len(len为2的幂次,最小为1),则每长度为len的区间内都保证有序

有了这个特点,再加上题目保证了除了归并排序就是插入排序,因为插入排序的特点看起来比较好判断,那么我们可以先判断一下该序列是否是插入排序的中间过程,若是的话,记录一下断点,从头到断点后的一个位置sort一下答案就出来了;若不是插入排序,那么就只能是归并排序了,我们可以先找出当前归并排序的归并长度len,将len乘二后模拟一遍归并排序的规则即可(即每个长度为len的区间都单独排序)

这里有几个细节需要注意一下,我也不知道算不算坑点:

  1. 题目只是说了要保证升序排序,但没保证是严格升序,虽然两个样例都给出的是严格升序,但是我们在判断的时候都要以非严格升序来判断,不然会有一组测试点过不去
  2. 在处理归并排序时,若数组长度n无法整除归并长度len,也就是说明最后肯定会剩下一段区间比len要小,这个需要单独排序
  3. 在获得归并长度len后,我们需要将其乘2后再进行新一轮的排序,此时需要注意一下,若len*2>n的情况下,我们只需要处理到n即可

代码:(自认为还是写的比较清晰易看的)

#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream> 
#include<unordered_map>
using namespace std;

typedef long long LL;

const int inf=0x3f3f3f3f;

const int N=110;

int n;

int a[N],b[N];

int check()//判断是否为插入排序 
{
	b[0]=INT_MIN;
	int i;
	for(i=1;i<=n;i++)
	{
		if(b[i-1]>b[i])
			break;
	}
	int mark=i;
	for(;i<=n;i++)
		if(a[i]!=b[i])
			return 0;
	return mark;
}

int getlen()//获得归并排序的长度 
{
	for(int len=1;len<=n;len<<=1)
	{
		for(int i=1;i+len-1<=n;i+=len)
		{
			int j=i+len-1;
			for(int k=i+1;k<=j;k++)
				if(b[k]<=b[k-1])
					return len;
		}
	}
	return n;//如果前面的最大长度len都通过了,那么下一次归并排序的长度最大到n结束 
}

void print()
{
	printf("%d",b[1]);
	for(int i=2;i<=n;i++)
		printf(" %d",b[i]);
	printf("\n");
} 

int main()
{
//  freopen("input.txt","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	for(int i=1;i<=n;i++)
		scanf("%d",b+i);
	int mark=check();
	if(mark)//插入排序 
	{
		puts("Insertion Sort");
		sort(b+1,b+1+mark);
	}
	else//归并排序 
	{
		puts("Merge Sort");
		int len=getlen();
		for(int i=1;i+len-1<=n;i+=len)//每长度为len的区间都单独排序 
			sort(b+i,b+i+len);
		sort(b+n/len*len+1,b+1+n);//最后剩余的那段也记得排序 
	}
	print();
	
	
	
	
	
	
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/102699173