根据维基百科的定义:
插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
归并排序进行如下迭代操作:首先将原始序列看成 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:
Merge Sort
1 2 3 8 4 5 7 9 0 6
/*
这里两个算法学的不好,今天学习一下算法再来看
然后这里行末不输出空格,所以这里选择数组进行输入数据;
这里相当于第一行数据是原始数据
第二行是排序过程的数据,属于中间状态;
我们可以用另外一个数组存放一组数据,直接对其进行排序;插入排序未排序的与原始数据
后段一致,可以进行比较判断插入排序;
现在要考虑怎么比较中间序列和原始序列;
这里N最大值为100,插入排序最坏的情况是逆序排放,就是降序排列的,每一个都要移动,
时间复杂度为O(n*n);
那么中间状态最坏的情况有100*100==10000种情况;
插入排序的前端有序,后端为原始序列;所以对于插入排序是比较好判别的,那么又因为测试序列
属于的排序算法唯一,所以不是插入排序的情况下就只能是归并排序;
然后还要输出算法的下一步,所以这里要实现两个算法;
这里要考虑归并的分组,就是怎么分组,怎么看出来时几个一组,这里计算机只能通过比较才能看
出来,不像人能够直观的看出来,这里我们分组只要让下标一致就可以了,
比如下标012345
0/2==0,1/2==0;
2/2==1,3/2==1;
4/2==2,5/2==2;
这里可以通过将下标除以基数得到对应的段数;然后对基数取余就得到段内的下标;
跟段地址还有点相通呢;
这里归并的段内排序我就直接用qsort了,方便一点;
用sort了,qsort不知道哪里出了点问题;
*/
#include<iostream>
#include<cstdlib>
#include <algorithm> //sort在算法头文件里;
using namespace std;
//以插入排序为基准判断排序方式;
int check(int* data,int* mid,int length){
//这里注意传入三个参数,一个是原始序列,一个是中间序列,一个是长度,根据原始求下一步;
//检查后端;这里前端是已经排序的,不方便比较,直接从后端没操作的数据比较;
int index=0; //标志不匹配位置的下标;
for(int i=length-1;i>=0;i--){ //这里插入排序后端数据未使用原始与中间序列一致;
if(data[i]!=mid[i]){
index=i;
break;
}
}
//检查前端是否是有序序列;
for(int i=0;i<index-1;i++){
if(mid[i]>mid[i+1]){
return -1; //这里返回就是归并排序;
}
}
return 1; //这里返回就是插入排序;
}
//输出数组;
void out(int* a,int length){
for(int i=0;i<length-1;i++){
cout<<a[i]<<' ';
}
cout<<a[length-1]<<endl;
}
//归并排序子函数;
void merge(int* data,int N,int seg){ //seg表示归并段长度;
for(int i=0;i<N;i+=seg){
if(i+seg<=N){
sort(data+i,data+i+seg);
}
else{
sort(data+i,data+N);
}
}
}
//比较函数;判断两个数列是否等价;
bool myequal(int* a,int* b,int length){
for(int i=0;i<length;i++){
if(a[i]!=b[i]){
return false;
}
}
return true;
}
//归并排序函数;
void mergeSort(int* data,int* mid,int N){ //segment是排序段长;
//这里归并选择用两个长度的段进行排序;
//这里并不需要按找归并的方式合并相邻的两个数列;
//只需要让两个数列合并成一个有序数列就好了;
int count=1; //归并段数的长度;
for(count=2;count<=N;count*=2){
if(myequal(data,mid,N)){ //如果相等只需要在归并一次即可退出;
merge(mid,N,count);
break;
}
else { //不相等继续归并;第一次一定不等;
merge(data,N,count);
}
}
}
//插入排序函数;
void insertSort(int* data,int* mid,int N){
int index=0; //标记不匹配的下标位置;
int temp; //存放即将操作的元素;
//找后端下标;
for(int i=N-1;i>=0;i--){ //这里插入排序后端数据未使用原始与中间序列一致;
if(data[i]!=mid[i]){
index=i;
break;
}
}
//进行一次插入排序;
temp=mid[index+1];
for(int i=index;i<N&&i>=0;i--){
if(temp<mid[i]){
mid[i+1]=mid[i];
}
else if(temp>=mid[i]){
mid[i+1]=temp;
break;
}
}
}
int main(){
//输入数据;
int N;
cin>>N;
//输入原始序列;
int data[N];
for(int i=0;i<N;i++){
cin>>data[i];
}
//输入中间序列;
int mid[N];
for(int i=0;i<N;i++){
cin>>mid[i];
}
//尝试判断排序类型;
char type='I'; //‘I’表示插入排序,'M'表示归并排序;
if(check(data,mid,N)==1){
cout<<"Insertion Sort"<<endl;
type='I';
}
else if(check(data,mid,N)==-1){
cout<<"Merge Sort"<<endl;
type='M';
}
//指向排序的下一步;
if(type=='I'){ //插入排序;
insertSort(data,mid,N);
out(mid,N);
}
else if(type=='M'){ //归并排序;
mergeSort(data,mid,N);
out(mid,N);
}
return 0;
}
/*
反思:这里不要陷入这个牛角尖,多用其他方法,都可以,然后就是排序算法的熟悉,还需要再进步
这道题还没有完全写完;部分正确;
*/