题目描述
一个中序二叉树遍历可以通过使用栈以非递归的方式实现。例如,假设当一个6节点的二叉树(其键值从1到6编号)被遍历时,栈操作是:push(1); push(2); push(3); pop(); pop(); push(4); pop(); pop(); push(5); push(6); pop(); pop(). 那么可以根据这个操作序列生成一个唯一的二叉树(如图1所示)。你的任务是给出这棵树的后序遍历序列。
输入规范:
每个输入文件包含一个测试案例。对于每个案例,第一行包含一个正整数N(≤30),这是树中总节点数(因此节点编号从1到N)。接下来的2N行描述了栈操作,格式为:“Push X”,其中X是被推入栈的节点索引;或者"Pop",意味着从栈中弹出一个节点。
输出规范:
对于每个测试案例,打印出相应树的后序遍历序列。保证存在解决方案。所有的数字必须由一个空格分隔,并且行尾不能有多余的空格。
Sample Input:
6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop
Sample Output:
3 4 2 6 5 1
代码展示
解题关键是根据出入栈的顺序来还原出二叉树,以下是相应的思路(这是笔者根据样例总结出来的):
①第一次PUSH的元素为头结点,先放入树中
②若栈顶的左孩子为空,那么此次PUSH的元素放入栈顶的左孩子处
③若栈顶的左孩子不为空,那么此次PUSH的元素就为上一个被pop的元素的右孩子(代码中用lastPop
表示)
④若栈顶为空,那么此次PUSH的元素为lastPop
的右孩子
当还原出二叉树后,进行一次递归后序遍历即可,我是将结果存储在全局变量数组res
中,这样可以有效地控制输出格式
#include <iostream>
#include <vector>
#include <stack>
#define tree int
#define MAXSIZE 30
#define Null -1
struct treeNode
{
int data;
tree left;
tree right;
}T[MAXSIZE];
std::vector<tree> res; //存储后序遍历的节点
tree buildTree (treeNode (&T)[MAXSIZE])
{
int K, n;
std::cin >> K;
std::string string;
int flag = 1;
std::stack<tree> s;
tree root = Null;
tree lastPop = Null;
for (int i = 1; i <= K * 2; i++)
{
std::cin >> string;
if (string == "Push")
{
std::cin >> n;
T[n].data = n;
T[n].left = Null;
T[n].right = Null;
//处理根节点
if (flag)
{
//数组编号和树结点编号都从1开始,树结点编号作为树的索引
root = n;
s.push(n);
flag = 0;
}
else if (!s.empty())
{
int top = s.top();
//若栈顶的左孩子为空,那么PUSH的元素放入栈顶的左孩子处
if (T[top].left == Null)
{
T[top].left = n;
}
//若栈顶的左孩子不为空,那么就为上一个被pop的元素的右孩子
else if (lastPop != Null)
{
T[lastPop].right = n;
}
s.push(n);
}
//若栈顶为空,那么为上一个被pop的元素的右孩子
else
{
if (lastPop != Null)
{
T[lastPop].right = n;
s.push(n);
}
}
}
else if (string == "Pop")
{
lastPop = s.top();
s.pop();
}
}
return root;
}
void postOrderTraversal(tree root, std::vector<tree>& res)
{
if (root > 0) //这里判断条件是root为正整数!
{
postOrderTraversal(T[root].left, res);
postOrderTraversal(T[root].right, res);
if (T[root].data > 0)
{
res.push_back(T[root].data);
}
}
}
int main()
{
tree r = buildTree(T);
postOrderTraversal(r, res);
//打印
std::cout << res[0];
for (size_t i = 1; i < res.size(); i++)
{
std::cout << ' ' << res[i];
}
return 0;
}