目录

​1,题目描述​

​题目大意​

​补充​

​ 堆排序​

​2,思路​

​3,AC代码​

​4,解题过程​

​第一搏​

​第二搏​


1,题目描述

PAT_甲级_1098 Insertion or Heap Sort (25point(s)) (C++)【堆排序】_甲级

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

题目大意

给出原始序列和部分排序后的序列,判断是插入排序还是堆排序。(和这一题很像​​*PAT_甲级_1089 Insert or Merge (25point(s)) (C++)【插入排序/归并排序】​​)

补充

堆排序​​@dreamcatcher-cx【图解排序算法(三)之堆排序】​

 堆排序

可用数组来模拟大根堆(增序排序时,使用大根堆,每次将最大值放置在末尾)。根节点为i时,左右孩子分别为2*i+1与2*i+2;

  • 设计下滤函数down;
  • 使用此函数构建大根堆;
  • 大根堆构建完成后,每次将根与数组中未排序部分的末尾交换(交换后,此元素已排序),并重新调整未排序部分的大根堆结构。每次可调整一个最大值到数组尾部;

 

2,思路

参考柳神的代码。 

根据排序的特点,进行判断:

插入排序:

  1. tar数组中前p个元素有序(从小到大),后面的元素与初始数组init相同;
  2. 若符合条件1,即认定为插入排序,只需对tar再进一步排序即可:sort(tar, tar + index + 1);

 堆排序:

  1. 原理:按增序排序时,将序列设置为大根堆。每次将大根堆的根节点数组中未排序部分的最后一个元素互换,然后重新调整树(数组形式)的结构:自上至下,与左右孩子中较大的孩子比较,若小于较大孩子,则与其交换,再以孩子节点为根,继续向下调整;若大于较大的孩子,则调整终止。调整函数down如下(下标从0开始,左孩子2*i+1,右孩子2*i+2):
  2. PAT_甲级_1098 Insertion or Heap Sort (25point(s)) (C++)【堆排序】_甲级_02

  3. 否定了插入排序后,便可确定为堆排序。从后向前遍历
  4. PAT_甲级_1098 Insertion or Heap Sort (25point(s)) (C++)【堆排序】_甲级_03

  5. ,找到第一个小于tar[0]的元素的位置p;
  6. 进行下一步堆排序,首先:
  7. PAT_甲级_1098 Insertion or Heap Sort (25point(s)) (C++)【堆排序】_C++_04

  8. 重新调整大顶堆结构
  9. PAT_甲级_1098 Insertion or Heap Sort (25point(s)) (C++)【堆排序】_1098_05

 

3,AC代码

#include<bits/stdc++.h>
using namespace std;
int init[101], tar[101], N; //init初始数组 tar部分排序数组
void down(int n){ //向下筛选
int i = 0, j = 2 * i + 1;
while(j < n){
if(j + 1 < n && tar[j] < tar[j+1])
j++; //选择较大的孩子节点
if(tar[i] < tar[j]){
swap(tar[i], tar[j]);
i = j;
j = 2 * i + 1;
}else break; //筛选结束
}
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d", &N);
for(int i = 0; i < N; i++)
scanf("%d", &init[i]);
for(int i = 0; i < N; i++)
scanf("%d", &tar[i]);
int p = 1, index;
while(p < N && tar[p-1] <= tar[p]) p++;
index = p;
while(p < N && tar[p] == init[p]) p++;
if(p == N){
printf("Insertion Sort\n");
sort(tar, tar + index + 1);
}else{
printf("Heap Sort\n");
p = N - 1;
while(p > 1 && tar[p] >= tar[0]) p--;
swap(tar[0], tar[p]);
down(p);
}
printf("%d", tar[0]);
for(int i = 1; i < N; i++)
printf(" %d", tar[i]);
return 0;
}

4,解题过程

第一搏

根据规律判断是哪种排序,并且在tar基础上再进行一次排序:

#include<bits/stdc++.h>
using namespace std;
int init[101], tar[101], N;//init初始数组 tar部分排序数组
void down(int n){
int i = 0, j = 2 * i + 1;
while(j < n){
if(j + 1 < n && tar[j] < tar[j+1])
j++;//选择较大的孩子
if(tar[i] < tar[j]){
swap(tar[i], tar[j]);
i = j;
j = 2 * i + 1;
}else break;
}
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d", &N);
for(int i = 0; i < N; i++)
scanf("%d", &init[i]);
for(int i = 0; i < N; i++)
scanf("%d", &tar[i]);
int p = 1, index;
while(tar[p-1] < tar[p]) p++;
index = p;
while(p < N && tar[p] == init[p]) p++;
if(p == N){
printf("Insertion Sort\n");
sort(tar, tar + index + 1);
}else{
printf("Heap Sort\n");
p = N - 1;
while(tar[p] > tar[0]) p--;
swap(tar[0], tar[p]);
down(p);
}
printf("%d", tar[0]);
for(int i = 1; i < N; i++)
printf(" %d", tar[i]);
return 0;
}

PAT_甲级_1098 Insertion or Heap Sort (25point(s)) (C++)【堆排序】_甲级_06

第二搏

注意到,题目上没有说序列中每个数字独一无二。于是在判断条件中加入了=号

PAT_甲级_1098 Insertion or Heap Sort (25point(s)) (C++)【堆排序】_PAT_07

PAT_甲级_1098 Insertion or Heap Sort (25point(s)) (C++)【堆排序】_1098_08