PAT_甲级_1098 Insertion or Heap Sort (25point(s)) (C++)【堆排序】
原创
©著作权归作者所有:来自51CTO博客作者再见萤火虫IT的原创作品,请联系作者获取转载授权,否则将追究法律责任
目录
1,题目描述
题目大意
补充
堆排序
2,思路
3,AC代码
4,解题过程
第一搏
第二搏
1,题目描述
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,思路
参考柳神的代码。
根据排序的特点,进行判断:
插入排序:
- tar数组中前p个元素有序(从小到大),后面的元素与初始数组init相同;
- 若符合条件1,即认定为插入排序,只需对tar再进一步排序即可:sort(tar, tar + index + 1);
堆排序:
- 原理:按增序排序时,将序列设置为大根堆。每次将大根堆的根节点与数组中未排序部分的最后一个元素互换,然后重新调整树(数组形式)的结构:自上至下,与左右孩子中较大的孩子比较,若小于较大孩子,则与其交换,再以孩子节点为根,继续向下调整;若大于较大的孩子,则调整终止。调整函数down如下(下标从0开始,左孩子2*i+1,右孩子2*i+2):
- 否定了插入排序后,便可确定为堆排序。从后向前遍历
- ,找到第一个小于tar[0]的元素的位置p;
- 进行下一步堆排序,首先:
- ;
- 重新调整大顶堆结构
- ;
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;
}
第二搏
注意到,题目上没有说序列中每个数字独一无二。于是在判断条件中加入了=号