PAT甲级--Insertion or Heap Sort
Posted C_YCBX Py_YYDS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PAT甲级--Insertion or Heap Sort相关的知识,希望对你有一定的参考价值。
更多PAT甲级题解尽在我的个人博客– acking-you.github.io
题目
题目大意
- 有很多题目实际不需要看懂题目,只需要看懂输入和输出,比如这题。
此题虽然题目较为学术,且比较长,实际总结下来就是,通过给你一个原数组序列,还有一个用插入排序或者是堆排序排了几轮的数组序列,你要根据这个序列判断所使用的排序方式,并且再以该排序方式往下排一轮。
解题代码拆解
这次由于我使用的接口化函数设计,也就是传入指针进行操作,没有采用全局变量,所以直接input操作写在main函数里面,省空间。
关键的判断函数
isInsert()
设计思路:假设为插入排序后的序列,通过一次循环,找到下一个要被排序的元素位置,按理来说,没有被排序的位置应该和原数组的序列情况一致,如果不一致,则不是插入排序。
//用于确定是否为插入排序,顺便返回此时待插入处理的位置
int isInsert(int* nums, int len) {
int i = 1;
for (; i < len; i++) {
if (nums[i - 1] > nums[i])
break;
}
for (int j = i; j < len; j++) {
if (original[j] != nums[j])
return -1;
}
return i;
}
堆排序和插入排序
插入排序
插入排序很简单,我这里直接写插入排序的每一轮处理函数来代替。
//插入排序的单步处理
void InsertSort(int* nums, int numSize, int i) {
int j = i;
int temp = nums[i];
for (; j > 0 && nums[j - 1] > temp; j--) {
nums[j] = nums[j - 1];
}
nums[j] = temp;
}
堆排序
对于一个完整的堆排序,分为两个过程:堆化+维持堆化。
建立大根堆,每次堆化找到最大值,为了位置堆的结构和排序,将堆顶与最后一个元素交换,然后更新对的范围到0~i-1
再次堆化,又能找到这个堆中的最大值,长此以往,便完成了排序。
- 对于堆排序中的每一轮:堆排中的每一轮都是缩小堆的范围,并继续维持大根堆,在堆范围以外的元素就是被排好的元素。所以重点在于从后往前找到已经排到了哪个位置,再进行一次交换和堆化便可完成一轮排序。
用于固定范围堆化的函数:sift_down()
//堆化,得到大根堆
//对于从0开始编号的二叉堆:
/* iparent = (i-1)/2,
ilchild = i*2+1,
irchild = i*2+2 */
void sift_down(int arr[], int start, int end) { // 计算父结点和子结点的下标
int parent = start;
int child = parent * 2 + 1;
while (child <= end) { // 子结点下标在范围内才做比较
// 先比较两个子结点大小,选择最大的
if (child + 1 <= end && arr[child] < arr[child + 1]) child++;
// 如果父结点比子结点大,代表调整完毕,直接跳出函数
if (arr[parent] >= arr[child]) return;
else {
// 否则交换父子内容,子结点再和孙结点比较
swap(arr[parent], arr[child]);
parent = child;
child = parent * 2 + 1;
}
}
}
不断堆化得到最大值进行排序:heap_sort()
void heap_sort(int arr[], int len) {
// 从最后一个节点的父节点开始 sift down 以完成堆化 (heapify)
for (int i = (len - 1 - 1) / 2; i >= 0; i--)
sift_down(arr, i, len - 1);
// 先将第一个元素和已经排好的元素前一位做交换,再重新调整(刚调整的元素之前的元素),直到排序完毕
for (int i = len - 1; i > 0; i--) {
swap(arr[0], arr[i]);
sift_down(arr, 0, i - 1);
}
}
确定堆排序到哪个位置的函数:findP
//用于找出堆排已经拍到了哪个位置的最大值。
int findP(int* nums, int len) {
int i = 0;
for (; i < len; i++) {
int val = *max_element(nums, nums + len - i);
if (nums[len - 1 - i] != val)
break;
}
return len - 1 - i;
}
整合代码进行提交
效率还行!
#include <bits/stdc++.h>
using namespace std;
int* original = nullptr;
//插入排序的单步处理
void InsertSort(int* nums, int numSize, int i) {
int j = i;
int temp = nums[i];
for (; j > 0 && nums[j - 1] > temp; j--) {
nums[j] = nums[j - 1];
}
nums[j] = temp;
}
//堆排序
void sift_down(int arr[], int start, int end) { // 计算父结点和子结点的下标
int parent = start;
int child = parent * 2 + 1;
while (child <= end) { // 子结点下标在范围内才做比较
// 先比较两个子结点大小,选择最大的
if (child + 1 <= end && arr[child] < arr[child + 1]) child++;
// 如果父结点比子结点大,代表调整完毕,直接跳出函数
if (arr[parent] >= arr[child]) return;
else {
// 否则交换父子内容,子结点再和孙结点比较
swap(arr[parent], arr[child]);
parent = child;
child = parent * 2 + 1;
}
}
}
// void heap_sort(int arr[], int len) {
// // 从最后一个节点的父节点开始 sift down 以完成堆化 (heapify)
// for (int i = (len - 1 - 1) / 2; i >= 0; i--)
// sift_down(arr, i, len - 1);
// // 先将第一个元素和已经排好的元素前一位做交换,再重新调整(刚调整的元素之前的元素),直到排序完毕
// for (int i = len - 1; i > 0; i--) {
// swap(arr[0], arr[i]);
// sift_down(arr, 0, i - 1);
// }
// }
//用于找出堆排已经拍到了哪个位置的最大值。
int findP(int* nums, int len) {
int i = 0;
for (; i < len; i++) {
int val = *max_element(nums, nums + len - i);
if (nums[len - 1 - i] != val)
break;
}
return len - 1 - i;
}
//用于确定是否为插入排序,顺便返回此时待插入处理的位置
int isInsert(int* nums, int len) {
int i = 1;
for (; i < len; i++) {
if (nums[i - 1] > nums[i])
break;
}
for (int j = i; j < len; j++) {
if (original[j] != nums[j])
return -1;
}
return i;
}
//统一打印结果函数
void print(int* nums, int len) {
cout << nums[0];
for (int i = 1; i < len; i++) {
cout << ' ' << nums[i];
}
}
int main() {
//@输入处理
ios::sync_with_stdio(false);
int N;
cin >> N;
int org[N], nums[N];
for (int i = 0; i < N; ++i) {
cin >> org[i];
} for (int i = 0; i < N; ++i) {
cin >> nums[i];
}
//@根据不同的排序方式进行答案的打印
original = org;
int flag = isInsert(nums, N);
if (flag != -1) {
cout << "Insertion Sort" << endl;
InsertSort(nums, N, flag);
print(nums, N);
} else {
cout << "Heap Sort" << endl;
int pos = findP(nums, N);
swap(nums[0], nums[pos]);
sift_down(nums, 0, pos - 1);
print(nums, N);
}
return 0;
}
以上是关于PAT甲级--Insertion or Heap Sort的主要内容,如果未能解决你的问题,请参考以下文章
PAT甲级1098 Insertion or Heap Sort (25 分)
PAT 1098 Insertion or Heap Sort (25)
PAT_A1098#Insertion or Heap Sort
1098. Insertion or Heap Sort (25)排序——PAT (Advanced Level) Practise
PAT-1098(Insertion Or Heap Sort)
1098. Insertion or Heap Sort (25)排序——PAT (Advanced Level) Practise