PAT.1127 ZigZagging on a Tree
哈哈,又是树。
最近老是遇到树,对于自底向上递归建树的策略已经熟稔了。
题目给出树的中序遍历和后序遍历,要求你确定这棵树,然后给出这棵树的zigzag遍历(正如其名,就是从左到右、从右到左如此往复的层序遍历)。
想想一般情况下的层序遍历用队列就可以很容易实现,那现在要两边整了————那就用deque吧。
然后再仔细思考一下用deque实现的基础上节点遍历的策略:
- 从右向左(队尾取)一定只能从队头插入(先插入右孩子再插入左孩子),因此得到的还是层序正序(从队头到队尾的正序),只是下一层从队头取
- 从左向右(队头取)一定只能从队尾插入(先插入左孩子再插入有孩子),因此的到的还是层序正序(从队头到队尾的正序),只是下一层从队尾取
这样就可以看出来,zigzag层序遍历的实现仅仅在于pop的方向和push的先后以及push的方向,因此我们只要设置一个标志位,在两种状态间来回转换就可以了。
题解
注意建树的时候函数参数要给出两个遍历中的共四个下标,同时对于单元素区间要直接返回节点,对于越界区间说明当前区间对应的孩子为空,返回 nullptr
即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
int val;
node *left;
node *right;
node(){
this->left = this->right = nullptr;
}
node(int t){
this->val = t;
this->left = this->right = nullptr;
}
};
int nodeCnt,inOrder[35],postOrder[35];
node *root;
deque<pair<node*,int> > tree;
//返回当前子树的根,[il,ir],[pl,pr]
node* build(int il,int ir,int pl,int pr){
//得到当前子树的根节点
int rootVal = postOrder[pr];
node *cNode = new node(rootVal);
if(il == ir || pl == pr) return cNode;
else if(il > ir || pl > pr) return nullptr;
//根据中序遍历划分左右子树
int inOrderRootIndex = il;
while(inOrderRootIndex <= ir && inOrder[inOrderRootIndex] != rootVal) inOrderRootIndex++;
cNode->left = build(il,inOrderRootIndex - 1,pl,pl + (inOrderRootIndex - il - 1));
cNode->right = build(inOrderRootIndex + 1,ir,pr - (ir - inOrderRootIndex),pr - 1);
return cNode;
}
int main(){
cin>>nodeCnt;
for(int i = 0 ; i < nodeCnt ; ++i) cin>>inOrder[i];
for(int i = 0 ; i < nodeCnt ; ++i) cin>>postOrder[i];
root = build(0,nodeCnt - 1,0,nodeCnt - 1);
bool popFromLeft = false;
tree.push_back({root,1});
while(!tree.empty()){
node *cNode = nullptr;
int cDepth = -1;
if(popFromLeft){
//从左向右取
cNode = tree.front().first;
cDepth = tree.front().second;
tree.pop_front();
if(cNode->left != nullptr) tree.push_back({cNode->left,cDepth + 1});
if(cNode->right != nullptr) tree.push_back({cNode->right,cDepth + 1});
if(!tree.empty() && tree.front().second != cDepth) popFromLeft = !popFromLeft;
}else{
//从右向左取
cNode = tree.back().first;
cDepth = tree.back().second;
tree.pop_back();
if(cNode->right != nullptr) tree.push_front({cNode->right,cDepth + 1});
if(cNode->left != nullptr) tree.push_front({cNode->left,cDepth + 1});
if(!tree.empty() && tree.back().second != cDepth) popFromLeft = !popFromLeft;
}
cout<<cNode->val;
if(!tree.empty()) cout<<' ';
}
cout<<endl;
}