1089 Insert or Merge(25 分)

最近已经被周围的准备九推的同学搞得头有点大,给我发各种必修成绩排名和综测排名。好吧,我自己也有点好奇呢!!!然后就和身边的人计算那些人有名额,自己是不是想得太多了,哈哈。

最近看了一下数据结构的排序知识,之前学合并排序都是学习它的递归算法,大家都知道递归算法存在一定的弊端,会使用到计算机的堆栈区,而且效率不是很好。好吧,它还是有优点的,就是解决某些问题的时候,这个方法又是多么的美妙(你肯定想到了那个例子对不对,汉诺塔,哈哈)。今天看到合并排序的非递归算法,当时就想自己理解好了之后写一篇博客,附带的题刚好在PAT上能找到,然后做了之后才开始写的。怎么说呢?感觉现在写代码,比较开心,最开心的时候莫过于解决了这个算法问题啦。

切换频道啦
首先看一下题:
1089 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、

插入排序的基本思想是:每次将一个待排序的元素,按其关键字的大小插入到已经安排好序的子表中的适当位置,直到全部元素插入完成为止。
(此语录摘自某某教材,嘿嘿,已经觉得解释得很形象了)

2、
合并排序的基本思想是:有序子列表归并成一个新的有序表。
这里介绍一下合并排序的非递归实现的思路,和递归实现也没有什么巨大区别。我们最开始的将R[0….n-1]看成是n个长度为1的有序序列表,然后从左到右进行两两合并,得到n/2(向上取整,抱歉,我不会在这里面插入特殊符号)个长度为2的有序序列表,然后再从使用循环从左到右进行两两合并,循环下去,直到得到一个长度为n的有序序列。这里要注意,当表的个数为奇数以及最后一个子表的长度小于length但是表的个数又为偶数这两种特殊情况。(length是什么,当然是子表的长度,最开始length为1,然后为2……以2倍的速度在变长)。对于表的个数为奇数的时候,最后一个表直接不用处理。当第二种情况,就使用merge将最后两个表像和之前的两两归并进行相同处理即可。
3、这道题呢,不是直接使用这两种方法对数据进行排序。我使用的方法:每次对初始数据进行一个元素的插入排序后,就和部分排好序的序列表匹配一下,以判断使用的是不是插入排序。同样的道理:每次对数据进行一趟合并之后,就和部分排好序的序列表匹配一下,判断是不是合并排序。如果其中一个匹配成功,就说明使用了此种排序方法,再调用该方法进行下一步骤的排序,将结果输出即可。如果两个都不匹配成功,就重复上述步骤,直到匹配时退出循环。

贴代码了:

#include <iostream>
using namespace std;
typedef int ElementType;
#define Max 100
int flag=0;//默认为0为第一个方法,1为第二个方法
int N;//存放需要排序的数组大小
int initial_A[Max];//存放原始数组
int Partial_Sort_A[Max];//存放已经部分排好序的数组
//和部分排好序的数据匹配
bool Match(ElementType A[]){
   int i;
   for(i=0;i<N;i++){
    if(A[i]!=Partial_Sort_A[i]){
        return false;
    }
   }
   return true;
}
//一次插入排序,每插入一次就和部分排好序的数组进行比较
//参数i表示第i次排序,指向下标为i的位置

bool Insertion(ElementType A[],int i){
   int j;
   ElementType tmp=A[i];
   for(j=i;j>0&&tmp<A[j-1];j--){
      A[j]=A[j-1];
   }
   A[j]=tmp;
   return Match(A);
}
/*1、一次合并*/
void Merge(ElementType A[],ElementType TmpA[],int L,int R,int RightEnd){
    int i;
     int C=L;
     int LeftEnd=R-1;
     int ElementSum=RightEnd-L+1;
     while(L<=LeftEnd&&R<=RightEnd){
        if(A[L]<A[R]) TmpA[C++]=A[L++];
        else  TmpA[C++]=A[R++];
     }
     while(L<=LeftEnd){
        TmpA[C++]=A[L++];
     }
     while(R<=RightEnd){
        TmpA[C++]=A[R++];
     }
     for(i=1;i<=ElementSum;i++,RightEnd--){
        A[RightEnd]=TmpA[RightEnd];
     }
}
/*2、对整个表进行一次归并*/
bool Merge_Pass(ElementType A[],ElementType TmpA[],int Length){
   int i;
   for(i=0;i<=N-2*Length;i=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);
   }
    return Match(A);
}
void OutPut(ElementType A[])
{
    int i;
    for(i=0;i<N-1;i++){
        cout<<A[i]<<' ';
    }
    cout<<A[i];
}
int main()
{
    cin>>N;
    int i;
    bool MatchFlag=false;
    ElementType InsertA[N];
    ElementType MergeB[N];
    ElementType Tmp[N];
    for(i=0;i<N;i++){
        cin>>initial_A[i];
        InsertA[i]=initial_A[i];
        MergeB[i]=initial_A[i];
    }
    for(i=0;i<N;i++){
        cin>>Partial_Sort_A[i];
    }
    i=1;
    int length=1;
    while(!MatchFlag){
        MatchFlag=Insertion(InsertA,i);
        i++;
        if(MatchFlag){
           break;
        }
        MatchFlag=Merge_Pass(MergeB,Tmp,length);
        length*=2;
        if(MatchFlag){
            flag=1;
            break;
        }
    }
    if(flag==0){
        cout<<"Insertion Sort"<<endl;
        Insertion(InsertA,i);
        OutPut(InsertA);
    }
    else{
        cout<<"Merge Sort"<<endl;
        Merge_Pass(MergeB,Tmp,length);
        OutPut(MergeB);
    }
    return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值