PTA刷题Basic篇——1035.插入与归并——Day(18)

问题描述

在这里插入图片描述
在这里插入图片描述

给出一段未排序序列,和排序过程的中间序列,判断使用了哪种排序方法,以及这个中间序列的下一步排序应该如何。

题目分析

这个问题其实并不简单,因为它的思路和一些方法比较难想。这就是乙级的题目,他不考你算法,不考你数据结构,只看你对一些概念,编程基础知识的掌握和解决问题的技巧。属于纯应用题目。
我们先来简单分析一下,插入排序和归并排序各自有什么特点。
插入排序特点:
插入排序的中间序列一定是前半部分有序,后半部分无序的。因为根据题目给出的维基百科定义,我们是依次排序的,前面排好以后后面还没来得及排呢。
归并排序特点:归并排序第一次排序基本上就会产生和原数列完全不一样的数列,因为他是k个一起排序(k是2的倍数),所以一次排序数列就会产生很大的变化,更不用说后半部分与原数列相等了。
所以这就变成了我可以利用的一个点,我们可以比较中间序列和原序列的后半部分,如果后半部分不完全相等,那我们就可以判定它使用了归并排序,否则使用了插入排序。
那么新的问题来了,我们如何判定从哪里开始算中间位置呢?
答案就是有序性。想想看,如果对于插入排序来说,前半部分一定有序,所以我们就依次判定,找到第一个无序的位置记录下来,然后从这个位置开始遍历,看后半部分与前半部分是否完全相等即可。
好啦,我们现在已经判断好了是归并排序还是插入排序了,接下来就是第二问,找出这种排序下的下一个中间序列。
如果第一问的答案是插入排序,我们就可以直接调用sort函数,将数列从头到中间位置+1进行排序(中间位置就是最后一个有序的位置,即我们所说的前半部分与后半部分的分割点)。
如果答案是归并排序,我们就要扩大序列进行排序了。在这里默认大家都了解归并排序的具体方法就不赘述了。最开始我们假设子问题规模为1,就是元素自己和自己排序,这是base case。逐个判断与中间序列是否完全一致,如果不一致,k=k*2,然后进行一次排序,这次是两两排序,最后一段不足k个就单独拿出来排序。我们不断进行上述循环,直到中间序列与这个正在排序的序列完全相等。我们就只需要再扩大规模一次进行排序,即可得到中间序列的下一步。(为了达到这一需求,我们的循环先判断相等,再进行扩大规模排序。)

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
//整数规模小于100,声明一个规模110的数组即可
int a[110], b[110];
int main() {
    scanf("%d", &n);
    for(int i = 0; i < n; i ++)
        scanf("%d", &a[i]);
    for(int i = 0; i < n; i ++)
        scanf("%d", &b[i]);
    int temp = 0;
    for(int i = 0; i < n - 1; i ++) {
        if(b[i] > b[i + 1]) {
            temp = i;
            break;
        }
    }
    int flag = true;
    for(int i = temp + 1; i < n; i ++) {
        //如果是插入排序,后面的一定没有关注到,所以此时我们后面应该是全等的,如果不等说明是归并排序
        if(a[i] != b[i]) {
            flag = false;
            break;
        }
    }
    if(flag) {
        printf("Insertion Sort\n");
        //再插入排序一次
        sort(a, a + temp + 2);
    }
    else
    {
        printf("Merge Sort\n");
        int k = 1, flag = 1;
        while(flag) {
            flag = 0;
            for(int i = 0; i < n; i++) {
                if (a[i] != b[i])
                    //直到a与b中的元素全部相等,则就只需要再归并一次即可
                    flag = 1;
            }
            k = k * 2;
            for (int i = 0; i < n / k; i++)
                sort(a + i * k, a + (i + 1) * k);
            //将最后一堆没有划为k个的序列单独排序
            sort(a + n / k * k, a + n);
        }
    }
    for(int i = 0; i < n; i ++) {
        printf("%d", a[i]);
        printf("%s", i != n - 1 ? " " : "\n");
    }
    return 0;
}

答题用时24min
Q35——finish√

原创文章 101 获赞 13 访问量 2307

猜你喜欢

转载自blog.csdn.net/weixin_44755413/article/details/105746801