解題思路:
1、區分是插入還是歸並
1)插入:前段有序,后段與初始序列一致。找到第一個破壞序列有序的下標,再繼續下一輪插入排序
2)歸並:段內有序,需確定最后歸並長度。從歸並段為2,4,8...開始找起,看是否每段段內有序,如果其中某段不滿足有序,則記下當前歸並段長度,再將歸並段*2即為下次歸並長度。
#include <stdio.h> #include <string.h> int Judge(int a[],int b[],int n) {//判斷是插入還是歸並段 int i,flag=0,pos=0; for(i=1; i<n; i++) { if(b[i-1]<=b[i]) { flag=1; } else { pos=i; break; } } if(flag) { for(i=pos; i<n; i++) { if(a[i]!=b[i]) { pos=0; break; } } } else pos=0; return pos; } void NextInsertionSort(int a[],int pos,int n) {//下一次插入排序 int i,tmp=a[pos]; int index; for(i=0; i<pos; i++) { if(a[i]>tmp) { index=i; break; } } for(i=pos-1; i>=index; i--) { a[i+1]=a[i]; } a[index]=tmp; } int k=0; void Merge(int a[],int low,int high,int mid) {//兩段歸並成一段 int i,j; int c[100]= {0}; for(i=low; i<=high; i++) { c[i]=a[i]; } i=low,j=mid+1; while(i<=mid&&j<=high) { if(c[i]<=c[j]) { a[k++]=c[i]; i++; } else { a[k++]=c[j]; j++; } } while(i<=mid) { a[k++]=c[i]; i++; } while(j<=high) { a[k++]=c[j]; j++; } } int GetMergeLen(int a[],int n) {//獲得當前歸並段的最大長度 int i,j; for(j=2; j<=n; j*=2) {//j<=n for(i=j; i<n; i=i+2*j)//i<n { if(a[i-1]>a[i]) break; } if(i<n) break; } return j; } void NextMergeSort(int a[],int low,int high,int len) {//下一次歸並 int i; for(i=low; i<=high; i+=len) { int mid=(i+i+len-1)/2; if(i+len-1<=high) { Merge(a,i,i+len-1,mid); } else if(mid<high) { Merge(a,i,high,mid); } } } int main() { int n; scanf("%d",&n); int i; int a[n],b[n]; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(i=0; i<n; i++) { scanf("%d",&a[i]); } for(i=0; i<n; i++) { scanf("%d",&b[i]); } int pos=Judge(a,b,n); if(pos) { printf("Insertion Sort\n"); NextInsertionSort(b,pos,n); } else { printf("Merge Sort\n"); int len=2*GetMergeLen(b,n);//下一次歸並段長度=當前歸並段長度*2 NextMergeSort(b,0,n-1,len); } for(i=0; i<n; i++) { if(i) printf(" "); printf("%d",b[i]); } return 0; }