案例7-1.2 插入排序还是归并排序 (25分)

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

归并排序进行如下迭代操作:首先将原始序列看成 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

代码如下:(有详解)

#include<stdio.h>
#include<stdlib.h>
/*    判断是否是插入排序     */
int IsInsertion(int *a, int *b, int N){
    int i,k;
    /*    找到非有序序列第一个元素的位置   */
    for(i=1;i<N;i++)
        if(b[i]<b[i-1]) break;
    k = i;			//用 k 储存非有序序列第一个元素位置
    /*   判断数组a[]和b[]剩下的序列是否一致,一致的话证明是插入排序,否则是归并排序   */
    for(;i<N;i++)
        if(b[i]!=a[i])  break;
    if(i==N)    return k;	//是插入排序的话返回非有序序列第一个元素的位置
    else    return 0;		//返回0表示不是插入排序
}
/*   输出结果的函数  没什么好说的     */
void PrintResults(int *b, int N){
    int i;
    printf("%d",b[0]);
    for(i = 1;i<N;i++){
        printf(" %d",b[i]);
    }
    printf("\n");
}

/*    插入排序再迭代一轮的结果    */
void NextInsertion(int *b,int N, int k){	//传入的 k 就是插入排序未排序序列第一个元素的位置    
    int i,tmp;
    printf("Insertion Sort\n");
    tmp = b[k];		
    /*   迭代一轮把tmp插入到有序序列中    */
    for(i = k-1;i>=0;i--){
        if(tmp<b[i])    b[i+1] = b[i];
        else    break;
    }
    b[i+1] = tmp;
    PrintResults(b ,N);
}
/*   判断归并排序当前的归并长度   (划重点了!)    */
/*    该方法来自陈越姥姥       */
int MergeLength(int *b, int N){
    int i, l;
    /*    首先让当前归并长度为 2   ,随着归并次数的增加归并长度不断乘2*/
    for(l = 2;l<=N;l*=2){
    /*  判断每两个归并段相邻的那两个元素是否有序     */
    /*   如先比较归并段1,2相邻的元素(即归并段1的最后一个元素与归并段2的第一个元素), 再去比较归并段3,4相邻的元素,以此类推    */
        for(i = l;i<N;i+=(l+l))
            if(b[i-1]>b[i]) break;	//找到了不符合条件的元素,此时l 就是当前归并长度
        if(i<N) break;
    }
    return l;
}
/*   归并排序再迭代一轮的结果    */
void NextMerge(int *b, int N){
    int i,p1,p2,p,L;
    int *tmp;	
    /*   tmp[]是一个临时数组   */
    tmp = (int *)malloc(sizeof(int)*N);
    printf("Merge Sort\n");
    L = MergeLength(b, N);	//L储存当前的归并长度
    p = 0;    //p指向tmp[]中当前处理的位置
    /*   开始归并    */
    for(i =0;i<(N-L-L);i+=(L+L)){	//两两归并长度为L的段
    	/*   p1, p2分别指向两个段当前的处理位置   */
        p1 = i;
        p2 = i+L;
        /*   归并两个段,并把数据存入临时数组  tmp   */
        while((p1<(i+L))&&(p2<(i+L+L))){
            if(b[p1]>b[p2])
                tmp[p++] = b[p2++];
            else
                tmp[p++] = b[p1++];
        }
        /*   处理剩余元素     */
        while(p1<(i+L))
            tmp[p++] = b[p1++];
        while(p2<(i+L+L))
            tmp[p++] = b[p2++];
    }
    /*    如果最后剩两段,执行归并    */
    if((N-i)>L){
        p1 = i;
        p2 = i+L;
        while(p1<(i+L)&&p2<N){	//注意这段代码与上面一段代码的区别就在于第二段的结束条件
            if(b[p1]<b[p2])
                tmp[p++] = b[p1++];
            else
                tmp[p++] = b[p2++];
        }
        while(p1<(i+L)) tmp[p++] = b[p1++];
        while(p2<N) tmp[p++] = b[p2++];
    }
    /*   最后只剩一段时直接存入临时数组   */
    else
        while(i<N)  tmp[p++] = b[i++];
    PrintResults(tmp, N);
}

int main(void){
    int N,i,k;
    int *a, *b;
    scanf("%d",&N);
    a = (int *)malloc(sizeof(int)*N);	//数组a[]储存原始序列
    b = (int *)malloc(sizeof(int)*N);	//数组b[]储存中间序列
    for(i =0;i<N;i++)
        scanf("%d",&a[i]);
    for(i =0;i<N;i++)
        scanf("%d",&b[i]);
    if(k =IsInsertion(a, b, N)){
        NextInsertion(b, N, k);
    }else{
        NextMerge(b ,N);
    }
    return 0;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值