中国大学MOOC-数据结构基础习题集、07-2、Insert or Merge
题目链接:http://www.patest.cn/contests/mooc-ds/07-2
题目分析:这是一道考察插入排序和归并排序的一道题。题目可能有点难以理解,这里稍加解释一下:
首先,输入的第一行是一个整型数,代表数据的个数。第二行是起始数据,排序从这里开始。第三行是目标(或者叫终止)数据,排序到这里结束。我们知道插入排序和合并排序是有很大不同的,如果是目标数据(我们暂且这么叫)是由插入排序生成的,就输出Insertion Sort;如果是目标数据是由归并排序生成的,就输出Merge Sort。不管是何种输入,都要输出这种排序的“下一步”。注意这里的“下一步”是“一大步”,也就是“一趟”归并排序。
特别说明:
1. 首先推荐一个函数:inplace_merge函数。它的作用和merge函数差不多,只不过是在一个容器中进行归并。
函数参数:inplace_merge(first,mid,last,compare); // 将[first,mid) 和 [mid,last)这两个区间进行归并成一个有序序列。
有了这个可以不用自己写merge了。但是此处博主并没有用到它。这里只是教大家用C++的STL解决实际问题。使用使需要引头文件#include <algorithm>。
如果相对merge类函数有更多了解,不妨阅读:http://www.cppblog.com/zhangyq/archive/2012/02/05/164060.html
2. 刚才说到博主这里没有用到merge类的函数,是因为博主压根没有用“归并排序”。当时博主的最直接的想法就是用sort替代真实的MSort和Merge。所以算是偷懒吧。另外程序中有点了乱,有的地方
3. 插入/合并排序可能出现一趟下来没有改变的情况,要输出有改变的才可以。也就是说你的输出不能和输入的第三行的那串数字相同。这点略坑。可以按照下面的方法测试下自己的代码。
建议测试用例:
测试用例一(这个没什么好说的,肯定都能过,为了与用例二比照):
测试用例二(重点):
代码分析:
每个函数前面都有注释,相信大家都能看得懂。
就像前面说的一样,博主只是用到了归并排序的思想,没有真正实现归并排序。想看归并排序的同学,可以看作业07-1,我刚刚更新了归并排序。这里我是借助了sort函数简化代码。这样做有点偷懒,但是却十分方便。
顺便解释一下,为什么在主函数中有a和aa两个数组。这是因为在判断IsInsert中,已经把a数组改变了,所以需要一个备份。就是这样,喵~
1 #include <iostream> 2 #include <algorithm> 3 4 #define NOTEXIST -1 5 6 using namespace std; 7 8 // 判断两个数组是否相等 9 bool isEqual(int a[], int b[], int n) 10 { 11 for(int i=0; i<n; i++) 12 if(a[i] != b[i]) 13 return false; 14 return true; 15 } 16 17 // 进行插入排序的移动元素操作 18 int moveElement(int i, int a[]) 19 { 20 int tmp = a[i]; 21 int j; 22 for(j=i; j>0 && a[j-1] > tmp; j--) 23 a[j] = a[j-1]; 24 a[j] = tmp; 25 return j; 26 } 27 28 // 判断是不是插入排序 29 int isInsertSort(int a[], int b[], int n) 30 { 31 for(int i=0; i<n; i++) 32 { 33 moveElement(i, a); 34 if(isEqual(a, b, n) == true) 35 return i; 36 } 37 return NOTEXIST; 38 } 39 40 // 非递归算法 41 bool MSort( int A[], int B[], int N ) 42 { 43 int step = 1; 44 bool myFlag = false; 45 while(step < N) 46 { 47 step *= 2; 48 for(int i=0; i<N; i=i+step) 49 { 50 int first = i; 51 int last = first + step; 52 if(last >= N) 53 last = N; 54 sort(A+first, A+last); 55 } 56 if(myFlag == true) 57 { 58 // 如果已经成功,走完了归并排序之后直接返回即可!注意此if语句应该位于下一个if语句之前!! 59 if(isEqual(A, B, N) == false) 60 return true; 61 } 62 if(isEqual(A, B, N) == true) 63 { 64 // 如果发现和目标数据相同,则置myFlag标识为true,代表已经成功,只需要再走一次归并排序即可! 65 myFlag = true; 66 } 67 } 68 return false; 69 } 70 71 // 输出数组内的元素 72 void outputElement(int x[], int n) 73 { 74 for(int i=0; i<n; i++) 75 { 76 if(i != n-1) 77 cout << x[i] << " "; 78 else 79 cout << x[i]; 80 } 81 cout << endl; 82 } 83 84 int main() 85 { 86 int n; 87 cin >> n; 88 int *a = new int[n]; 89 int *aa = new int[n]; 90 for(int i=0; i<n; i++) 91 { 92 cin >> a[i]; 93 aa[i] = a[i]; 94 } 95 96 int *b = new int[n]; 97 for(int j=0; j<n; j++) 98 cin >> b[j]; 99 int IS = isInsertSort(a, b, n); 100 if(IS != NOTEXIST) 101 { 102 cout << "Insertion Sort" << endl; 103 while(isEqual(a, b, n) == true) 104 { 105 IS = moveElement(IS+1, a); 106 } 107 outputElement(a, n); 108 } 109 else 110 { 111 cout << "Merge Sort" << endl; 112 MSort(aa, b, n); 113 outputElement(aa, n); 114 } 115 return 0; 116 }
AC成果: