In computer science, a heap is a specialized tree-based data structure that satisfies the heap property: if P is a parent node of C, then the key (the value) of P is either greater than or equal to (in a max heap) or less than or equal to (in a min heap) the key of C. A common implementation of a heap is the binary heap, in which the tree is a complete binary tree. (Quoted from Wikipedia at https://en.wikipedia.org/wiki/Heap_(data_structure))
One thing for sure is that all the keys along any path from the root to a leaf in a max/min heap must be in non-increasing/non-decreasing order.
Your job is to check every path in a given complete binary tree, in order to tell if it is a heap or not.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (1<N≤1,000), the number of keys in the tree. Then the next line contains N distinct integer keys (all in the range of int), which gives the level order traversal sequence of a complete binary tree.
Output Specification:
For each given tree, first print all the paths from the root to the leaves. Each path occupies a line, with all the numbers separated by a space, and no extra space at the beginning or the end of the line. The paths must be printed in the following order: for each node in the tree, all the paths in its right subtree must be printed before those in its left subtree.
Finally print in a line Max Heap if it is a max heap, or Min Heap for a min heap, or Not Heap if it is not a heap at all.
Sample Input 1:
8
98 72 86 60 65 12 23 50
Sample Output 1:
98 86 23
98 86 12
98 72 65
98 72 60 50
Max Heap
Sample Input 2:
8
8 38 25 58 52 82 70 60
Sample Output 2:
8 25 70
8 25 82
8 38 52
8 38 58 60
Min Heap
Sample Input 3:
8
10 28 15 12 34 9 8 56
Sample Output 3:
10 15 8
10 15 9
10 28 34
10 28 12 56
Not Heap
这道题帮我复习了如何建立顺序树,以及顺序树如何写dfs进行深搜遍历每条路径,和如何检查一棵二叉树是否是一个堆。
题目要求是从右到左打印出所有从根到叶子的路径,并判断这个二叉树是小根堆、大根堆,还是不是堆。
显然这道题用顺序树表示会简单很多,因为这道题范围本来就不大,才1000,开个元素数1005的int数组就够了;其次,顺序树将下标当做地址,不需要自己构造数据结构,也不容易段错误了;其三,顺序树的遍历极其方便。
下面上代码。注意注释。
- 顺序树:对一个n个节点的二叉树,顺序树结构的根节点下标恒置为1,对每个节点i,其左子树节点固定为2i,右子树节点固定为2i+1,如果这两个值均超过了n,则表示i为叶子结点,反之,为非叶节点。
- 深搜回溯遍历顺序树:首先确定递归边界,如果左右子树的值超过了2*i,2*i+1,就检测当前i<=n吗?如果是,就打印当前路径。路径如何寻找?回溯法。由于要求从右向左遍历,所以首先存入右子树,2*i+1,别忘了当前节点路径搜索完了时,要删掉这个节点,就是vector的pop_back操作;然后再存入左子树,2*i,搜索完时,也别忘了pop_back。
- 堆检验:只需要设置两个标识变量maxheap和minheap,初始全置为1,从i=2开始循环,判断顺序树中下标i/2与i元素的大小关系。碰到一个a[i/2]<a[i],就把maxheap设为0;碰到一个a[i/2]>a[i],就把minheap设为0;如果最后恰好一个0一个1,就是对应的堆,否则就不是堆。
#include <bits/stdc++.h>
#define N 1005
using namespace std;
void dfs(int now);
int a[N],n,mx=1,mn=1;
vector<int> v;
int main() {
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
v.push_back(a[1]);
dfs(1);
for (int i=2;i<=n;i++) { //从2开始,检测i/2,而不是i*2,这样不需要处理下标越界,简单了很多
if (a[i/2]>a[i]) mn=0;
if (a[i/2]<a[i]) mx=0;
}
if (mn==0&&mx==1) printf("Max Heap\n");
else printf("%s\n",(mn==1&&mx==0)?"Min Heap":"Not Heap");
return 0;
}
void dfs(int now) {
if (2*now>n&&2*now+1>n) { //如果当前节点的(可能的)子节点会超过n,也就是当前节点如果不存在
if (now<=n) { //说明该路径已经到最后一层,如果now仍未越界,则可开始打印路径
for (int i=0;i<(int)v.size();i++)
printf("%d%c",v[i],i!=(int)v.size()-1?' ':'\n');
} //外部会自动pop,在搜到最深路径时不用清除v中所有数据
}
else {
v.push_back(a[2*now+1]);
dfs(2*now+1);
v.pop_back(); //回溯,记住
v.push_back(a[2*now]);
dfs(2*now);
v.pop_back();
}
}
复杂度:约为n/2条路径,每条路径logn长度,则复杂度约为O(nlogn).