题目链接:PAT【甲级】1155
题目简述:按完全二叉树层次遍历的方式,给定一行数字。要求去判断给定的这些数字(也即这个二叉树)是不是个二叉堆,如果是堆是最大堆还是最小堆。
#include<bits/stdc++.h>
using namespace std;
int N, batch = 0;
long long table[1000] = {0};
vector<vector<int>> store(501);
string checkAns[3] = {"Max Heap", "Min Heap", "Not Heap"};
void dfs(int beg, int layer){
if(beg >= N)
return;
bool isHasRChild = false;
store[batch].push_back(table[beg]);
if(2 * beg + 2 < N){
dfs(2 * beg + 2, layer + 1);
isHasRChild = true;
}
if(2 * beg + 1 < N){
if(isHasRChild){//一定要考虑到这一点,不然有逻辑漏洞
batch++;
store[batch].assign(store[batch - 1].begin(), store[batch - 1].begin() + layer);
}
dfs(2 * beg + 1, layer + 1);
}
}
int main(){
cin >> N;
for (int i = 0; i < N;i++)
cin >> table[i];
dfs(0, 1);
bool isAllOrder_min = false;
bool isAllOrder_max = false;
for (int i = 0; i <= batch;i++){
int pre = store[i][0], temp;
cout << store[i][0];
for (int j = 1; j < store[i].size();j++){
cout << " " << store[i][j];
temp = store[i][j];
if(temp > pre){
isAllOrder_min = true;
}
if(temp < pre){
isAllOrder_max = true;
}
pre = temp;//这行没写,都能过测试点,而且还只有一个没过
}
cout << endl;
}
if(!isAllOrder_max && isAllOrder_min)
cout << checkAns[1] << endl;
else if(!isAllOrder_min && isAllOrder_max)
cout << checkAns[0] << endl;
else
cout << checkAns[2] << endl;
return 0;
}
写这个递归我吐了。我的这个逻辑有点混乱,有点复杂,不过幸好能过,恶心坏我了。
看题目,就是一个二叉树的遍历,这个变形的遍历方式要求我们去记录路径,最后将其输出。因为涉及到二叉树的遍历,很自然想到递归的写法,又由于是完全二叉树,一些下标特性也是可以使用的。所以要往递归方向靠。
当然能够想到这样的最初形式:
void dfs(int beg){
if(beg >= N)
return;
store[batch].push_back(table[beg]);
dfs(2 * beg + 2);
dfs(2 * beg + 1);
}
- 记录路径。要去把路径记录下来啊,所以要对
batch
进行操作,会发现一个路径完成后,会转向左孩子遍历,所以batch
增加的操作是在转向左孩子时来判断的。 - 预先判断能否进行遍历。这样的话是可以避免在叶子节点处,我们因为要转向左兄弟遍历时,而无端使得
batch
增加的情况。但其实这种情况可以通过下面要说的增加标记来解决。 - 增加标记。增加标记是因为当父节点只有一个左孩子时,我们因右孩子为空,而转向左孩子时出现
batch
无故增加的情况。
其他的就是简单的判断而已了。至此,我的想法就结束了。但下面我要说一下我的问题:
对于增加标记来解决batch
无故增加的问题,其实并不科学。因为这是一颗完全二叉树,才可以这样写,不然仍然不能够解决。
而且我这个递归写的其实也不怎么好,没有突出利用好回溯这一特性,看过别人的博客后才深深明白这一缺陷,利用好这一点,上面我为之困恼的问题就都没有了,而且代码也能更精简一些。