插入排序+非递归归并排序 09-排序2 Insert or Merge (25分)

09-排序2 Insert or Merge (25分)

According to Wikipedia:

Insertion sort iterates, consuming one input element each repetition, and growing a sorted output list. Each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there. It repeats until no input elements remain.

Merge sort works as follows: Divide the unsorted list into N sublists, each containing 1 element (a list of 1 element is considered sorted). Then repeatedly merge two adjacent sublists to produce new sorted sublists until there is only 1 sublist remaining.

Now given the initial sequence of integers, together with a sequence which is a result of several iterations of some sorting method, can you tell which sorting method we are using?

Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤100). Then in the next line, N integers are given as the initial sequence. The last line contains the partially sorted sequence of the N numbers. It is assumed that the target sequence is always ascending. All the numbers in a line are separated by a space.

Output Specification:
For each test case, print in the first line either “Insertion Sort” or “Merge Sort” to indicate the method used to obtain the partial result. Then run this method for one more iteration and output in the second line the resuling sequence. It is guaranteed that the answer is unique for each test case. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input 1:

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

Sample Output 1:

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

Sample Input 2:

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

Sample Output 2:

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

解题
写出插入排序与归并排序,在每次排序后进行判定,若与给定数列相同顺序,则说明为该排序方法,并进行一步排序后输出;

1.输入函数
T用于插入排序;
I用于归并排序;

#include<iostream>
using namespace std;
#define MAXN 101

int N;
int T[MAXN]; 
int I[MAXN];
int Result[MAXN];
void input()
{
	cin>>N;
	for(int i=0;i<N;i++)
	cin>>T[i];
	
	for(int i=0;i<N;i++) I[i]=T[i];
	
	for(int i=0;i<N;i++)
	cin>>Result[i];
}

2.插入排序
从下标为1到N-1,逐个与前面的数比较,前面数大则大数后移,前面数小则插入其后;

void InsertSort()
{
	int i;
	
	for(int i=1;i<N;i++)
	{
		int tmp=T[i];
		int j;
		for(j=i;j>0&&T[j-1]>tmp;j--)
			T[j]=T[j-1];
		T[j]=tmp;
		
		//判断是否与某一步骤吻合 
		int flag=1;
		
		for(int t=0;t<N;t++)
		{
			if(T[t]!=Result[t])
				{
					flag=0;
					break;
				 }	  
		}

		//执行输出 
		if(flag==1){
			cout<<"Insertion Sort"<<endl;
			tmp=T[i+1];
			for(j=i+1;j>0&&T[j-1]>tmp;j--)
				T[j]=T[j-1];
			T[j]=tmp;
			for(int t=0;t<N-1;t++)
			cout<<T[t]<<" ";
			cout<<T[N-1];
			return;
		}
	}
}

3.归并排序(非递归)
归并:
把A的L ~ R-1部分和R ~ Rightend部分排序后放TmpA,再由TmpA复制回来;

void Merge( int A[], int TmpA[], int L,int R, int RightEnd)
 { //将有序的A[L]~A[R-1]和A[R]~A[RightEnd]归并成一个有序序列
 	int LeftEnd,tmp;
	int i;
	int Num;
	
	LeftEnd = R-1;
	tmp=L; //保存起始位置
	Num = RightEnd-L+1; //计算要归并的数的个数
	
	while(L <= LeftEnd && R<=RightEnd){ //两个都没有遍历完
		if(A[L]<=A[R])
			TmpA[tmp++]=A[L++];
		else
			TmpA[tmp++]=A[R++]; 
	} 
	
	while(L<=LeftEnd){   //若右边完了,左边还有,则左边添进去 
		TmpA[tmp++]=A[L++];
	}
	while(R<=RightEnd){
		TmpA[tmp++]=A[R++];
	}
	
	for( i =0;i<Num;i++,RightEnd--)
		A[RightEnd]=TmpA[RightEnd];       //把这些数全部拷贝到A中 
 }

将A中每length长度的数成对归并至TmpA,当尾部还剩一对时,再进行一次归并,若尾部只剩单个,则直接复制回A。

void Merge_pass(int A[], int TmpA[],int N,int length)
{ //两两归并相邻有序序列
	int i,j;
	
	for(i=0;i<=N-2*length;i+=2*length)  //处理成对的部分
		Merge(A,TmpA,i,i+length,i+2*length-1);
		
	if(i+length<N)
		Merge(A,TmpA,i,i+length,N-1);
	else 
		for(j=i;j<N;j++) TmpA[j]=A[j];       //把A赋值给TmpA	 
	
}

完整归并,当length初始化为1,从单个数字开始归并,直到所有数都归并完成;
期间若判定函数判定当前数列与给定数列相同,即可判断此次为归并排序,输出。

int Judge(int F[])
{
	int flag=1;
	for(int i=0;i<N;i++)
	{
		if(I[i]!=Result[i])
		{
			flag=0;
			break;
		}
	}
	if(flag==0) return 0;
	if (flag==1) return 1;
}

void MergeSort()
{
	int * TmpA=new int [N];
	int length =1;
	

		while(length<N)
		{
			Merge_pass(I,TmpA,N,length);
			length *=2;
			if(Judge(TmpA)) {
			cout<<"Merge Sort"<<endl;
			Merge_pass(TmpA,I,N,length);
			for(int i=0;i<N-1;i++)
			cout<<I[i]<<" ";
			cout<<I[N-1];
				return;
			}
//			Merge_pass(TmpA,I,N,length);
//			length*=2;
//			if(Judge(I)){
//			cout<<"Merge Sort"<<endl;
//			Merge_pass(I,TmpA,N,length);
//			for(int i=0;i<N-1;i++)
//			cout<<TmpA[i]<<" ";
//			cout<<TmpA[N-1];
//				return;
//			}
			
		}
		delete TmpA;

}

因为Merge函数每次返回后A与TmpA都相同,故这里循环只要一次判断即可;

4.main函数

int main()
{
	input();
	InsertSort();
	MergeSort();
}

注意点
归并排序递归方法难以得到每一步的结果,
非递归方法可以得到每一步的结果。

较方便的方法

首先判断是否为插入排序:
前面按从小到大顺序排序,不满足后后面与原先数组顺序相同,则为插入排序;
否则为归并排序;
难点
如何得到归并排序的下一步?

for ( l=2; l<=N; l*=2 )

假设归并的个数为2,看第2和第3是否满足;查看第2+2i和第3+2i是否满足;
若都满足,则i至少为4;
若有不满足的,则当前i为已归并的次数,则再归并每2i个数即可;

发布了105 篇原创文章 · 获赞 6 · 访问量 4946

猜你喜欢

转载自blog.csdn.net/BLUEsang/article/details/105555424