0
点赞
收藏
分享

微信扫一扫

插入排序还是归并排序

dsysama 2022-04-21 阅读 49
算法c++

根据维基百科的定义:

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。

现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?

输入格式:

输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。

输出格式:

首先在第 1 行中输出Insertion Sort表示插入排序、或Merge Sort表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。

输入样例 1:

10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0

输出样例 1:

Insertion Sort
1 2 3 5 7 8 9 4 6 0

输入样例 2:

10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6

输出样例 2:

Merge Sort
1 2 3 8 4 5 7 9 0 6

 思路:如果是插入排序的话,那么就会b就会先有一段非递减序列,假设非递减序列到下标为j结束,那么数组b从下标j+1到n-1的数和原数组a一样。如果不是这样的话就是归并排序。

 对插入排序来说,找到异常的数的下标,然后从这个下标开始往前走,如果找到比他小的数就把他放在比他小的数后面结束,如果这个数比他大,就把这个数往后挪。

对归并排序来说,找到头两个非递减序列的长度cnt1和cnt2,因为归并排序每次是两个和两个序列合并,所以取他俩的最小值cnt之后找一下能够两两配对的下标最长到哪,假设到x,然后我们对这两两配对的区间进行排序,最后处理一下最后没被配对的序列排个序就好了。

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int a[105];
int b[105];
int main(){
	int n,x;//用x来记录异常顺序的数
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	for(int i=0;i<n;i++){
		cin>>b[i];
	}
	bool f=true;
	int idx;//用idx来记录异常顺序数的下标
	for(int i=0;i<n;i++){
		if(b[i]<b[i+1])continue;//如果正常,直接跳过
		else{
			idx=i+1;//否则记录一下异常数的下标和数
			x=b[i+1];
			break;
		} 
	}
	for(int i=idx;i<n;i++){//检查异常数后面的数是否和原数组后面的数一样
		if(a[i]!=b[i]){//如果不一样就是归并排序
			f=false;
			break;
		}
	}
	if(f){
		printf("Insertion Sort\n");
		for(int i=idx;i>=0;i--){//如果是插入排序的话就从异常的数开始往前看
			if(i==0)b[i]=x;//如果走到首个元素了就把异常元素放进首个元素里
			else{
				if(x>b[i-1]){//找到比异常元素小的位置,把异常元素放他后面
					b[i]=x;
					break;
				}else{
					b[i]=b[i-1];//如果他比异常元素大,把他往后挪
				}
			}
		}
		for(int i=0;i<n;i++){
			if(i!=0)printf(" ");
			printf("%d",b[i]);
	}
	}
	else{
		printf("Merge Sort\n");
		int cnt1=1,cnt2=1,cnt,z=0;//cnt1是第一个非递减序列的长度,cnt2是第二个递减序列的长度
		int flag=0;//记录是在算第一个长度还是第二个长度
		for(int i=1;i<n;i++){
			if(flag==0){//如果在算第一个长度
				if(b[i-1]<=b[i]){//当他递增的时候长度++
					cnt1++;
				}else{//否则的话开始第二个长度的计算
					flag=1;
				}
			}else{//第二个长度计算
				if(b[i-1]<=b[i]){//如果递增长度就++
					cnt2++;
				}else break;//否则结束运算
			}
		}
		cnt=min(cnt1,cnt2);//取两个序列最短的那个长度
		int x=n/(2*cnt)*(2*cnt);//这里是在计算当前面的序列两两配对后的长度(
		while(z+2*cnt<=n){//这个z是用来记录每次排序的头下标,这个操作是用来对两两配对的序列进行整合排序
			sort(b+z,b+z+2*cnt);//将两两配对的区间里的数划分在一起排序
			z+=2*cnt;//更新排序的下标
		}
		sort(b+x,b+n);//对最后没有配对的序列进行排序
		for(int i=0;i<n;i++){
			if(i!=0)printf(" ");
			printf("%d",b[i]);
		}
	} 
	
	return 0;
}
举报

相关推荐

0 条评论