PAT甲级刷题记录——1098 Insertion or Heap Sort (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.

Heap sort divides its input into a sorted and an unsorted region, and it iteratively shrinks the unsorted region by extracting the largest element and moving that to the sorted region. it involves the use of a heap data structure rather than a linear-time search to find the maximum.

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 “Heap 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 resulting 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 6 0
6 4 5 1 0 3 2 7 8 9

Sample Output 2:

Heap Sort
5 4 3 1 0 2 6 7 8 9

思路

这题就是考察排序(但跟别的题无脑排序不一样,这题需要对经典排序算法有所了解),题目大意就是给出一个数字N,然后第一行给出含N个数字的初始序列,第二行再给出排序排到一半的序列。让你判断一下,这个排到一半的序列是经过什么排序来的(插入排序?堆排序?),判断完了之后,再给出下一步的序列。

首先如何判断插排和堆排,很简单,只要看第二个元素是不是比第一个元素大就行了。如果是插入排序,那么第二行序列的前面某一段一定是升序的(样例1里就是1 2 3 7 8),因此,第二个元素肯定比第一个元素大如果是堆排序,那么第二行序列的后面某一段一定是升序的(样例2里就是7 8 9,但是2不能算在里面,这个判断起来比较麻烦,正因如此,我们判断堆排序下一步的时候要重新开始排一遍),虽然堆排序后面判断起来比较麻烦,但是堆排序的前一段肯定满足大顶堆的要求(要排除升序序列,肯定是大顶堆),也就是说,第二个元素肯定比第一个元素小(孩子的权值要比父亲的权值小)。

然后来做排序的下一步:
①插入排序:很简单,找到第一个不满足升序的元素下标index,然后对1~index范围用sort()函数排个序就好了(这里要注意的是,sort()函数范围是左闭右开,第二个参数应写范围的下一个地址,也就是到index+1)。
②堆排序:其实也很简单,但是我因为向下调整的函数写错了……卡了好久(晕)。因为我们有原始序列,所以干脆对原始序列进行堆排序,但是,前提是要先让原始序列成堆(不然排啥序),我这里直接用了make_heap()函数,同样的,区间也是左闭右开的,第二个要写到N+1。原始序列成堆之后,就按照堆排序的算法,从后向前遍历,假设当前访问的是第i个元素,那么每次交换第i个元素和堆顶元素(也就是第1个元素),再做一次向下调整。这里需要加一步的是,每次做完向下调整,就看看是不是和给出的第二行序列相同,如果相同,那么人为再进行一次交换和向下调整的操作,然后直接break掉即可,这样得到的就是堆排序下一步的序列了。

代码

#include<cstdio>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn = 110;
int initialSeq[maxn] = {0};
int partialSorted[maxn] = {0};
bool isSame(int a[], int b[], int len){
    for(int i=1;i<=len;i++){
        if(a[i]!=b[i]) return false;
    }
    return true;
}
void downAdjust(int low, int high){
    int i = low, j = i*2;
    while(j<=high){
        if(j+1<=high&&initialSeq[j+1]>initialSeq[j]){
            j = j+1;
        }
        if(initialSeq[j]>initialSeq[i]){
            swap(initialSeq[j], initialSeq[i]);
            i = j;
            j = i*2;
        }
        else break;
    }
}
int main(){
    int N;
    scanf("%d", &N);
    for(int i=1;i<=N;i++){
        scanf("%d", &initialSeq[i]);
    }
    for(int i=1;i<=N;i++){
        scanf("%d", &partialSorted[i]);
    }
    if(partialSorted[2]>partialSorted[1]){
        //如果第二个元素比第一个元素大,说明是插入排序
        //因为堆排序剩余的元素依然满足大顶堆的结构,结点1的孩子2应该一定比它小
        printf("Insertion Sort\n");
        int index = 0;//记录第一个不满足升序的数
        for(int i=1;i<N;i++){
            if(partialSorted[i+1]<partialSorted[i]){
                index = i+1;
                break;
            }
        }
        sort(partialSorted+1, partialSorted+index+1);//加入index号元素,并排序
        for(int i=1;i<=N;i++){
            if(i==1) printf("%d", partialSorted[i]);
            else printf(" %d", partialSorted[i]);
        }
    }
    else{
        printf("Heap Sort\n");
        make_heap(initialSeq+1, initialSeq+N+1);
        for(int i=N;i>1;i--){
            swap(initialSeq[i], initialSeq[1]);
            downAdjust(1, i-1);
            if(isSame(initialSeq, partialSorted, N)==true){
                i--;//人为再进行一次循环,然后break
                swap(initialSeq[i], initialSeq[1]);
                downAdjust(1, i-1);
                break;
            }
        }
        for(int i=1;i<=N;i++){
            if(i==1) printf("%d", initialSeq[i]);
            else printf(" %d", initialSeq[i]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值