题目
题目大意
给出一棵二叉树,树的元素是运算符号或字母、数字、字符串,要求按中序遍历输出算式,算式优先级用括号来表示。
思路
肯定要构建树,因为有特殊字符,所以用结构体数组来存储,每个节点都包含id,name(该节点实际表示的字符),左孩子和右孩子。然后再找到根节点方便接下来的遍历。
接着观察树的结构图和输出样例,发现每一个子树都被左右括号所包裹,除了叶子节点。因此在中序遍历时,可以用字符串res来记录最终结果,遍历左子树或右子树前,res插入一个'(',遍历完左子树或右子树后,res插入一个')'。
需要注意,叶子节点前后是没有括号的,因此可以加空格来区分哪个是叶子节点的括号,等遍历结束后,删除空格附近的括号即可。
代码
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct node{
int id;
string name;
int lchild, rchild;
};
int n;
vector<node> v;
string res = "";
void traverseTree(int root){
if (v[root].lchild == 0 && v[root].rchild == 0){
res += " ";
res += v[root].name;
res += " "; // 用空格作记号,标明应该删除的括号
return;
}else{
if (v[root].lchild){
res += "(";
traverseTree(v[root].lchild);
res += ")";
}
res += v[root].name;
if (v[root].rchild){
res += "(";
traverseTree(v[root].rchild);
res += ")";
}
}
} // 中序遍历,并记录res
int main(){
cin >> n;
v.resize(n + 1);
for (int i = 1; i <= n; i++){
cin >> v[i].name;
v[i].id = i;
int lchild, rchild;
cin >> lchild >> rchild;
v[i].lchild = v[i].rchild = 0;
if (lchild != -1){
v[i].lchild = lchild;
}
if (rchild != -1){
v[i].rchild = rchild;
}
} // 构建树
int root;
vector<bool> b(n + 1); // 节点有没有被当作子节点
for (int i = 1; i <= n; i++){
if (v[i].lchild){
b[v[i].lchild] = true;
}
if (v[i].rchild){
b[v[i].rchild] = true;
}
}
for (int i = 1; i <= n; i++){
if (!b[i]){
root = i;
break;
}
} // 查找根节点
traverseTree(root);
for (int i = 0; i < (int)res.size() - 1; i++){
if (res[i] == '(' && res[i + 1] == ' '){
res.erase(i, 2);
i--;
}
if (res[i] == ' ' && res[i + 1] == ')'){
res.erase(i, 2);
i--;
}
} // 根据空格记号,删除多余的括号
for (int i = 0; i < (int)res.size(); i++){
if (res[i] == ' '){
res.erase(i, 1);
i--;
}
} // 测试点2格式错误,将多余的空格去掉
cout << res << endl;
return 0;
}