#include using namespace std; const int N = 30; /* 思路 1、数据处理,通过记录入度,找到入度为0的点,找到根节点 2、二元运算必须有符号右边那个式子,即根据数据构建完树后的右孩子 故在递归遍历树的时候,只要判断该节点是否有孩子, 然后返回的字符串数: 递归左子树的string值 + 该节点的string值 + 递归右子树的string值 3、如果该节点不是根节点,则在该返回值的左右两边加上括号 4、最后输出返回值 黄海总结: 1、乍一看此题,感觉无从下手,因为不知道每个点都是什么节点号!后来慢慢从测试用例1中发现, data 都是什么 *,a,b,-,c之类,不是节点号,应该是具体的操作符,也就是值。 那节点号在哪里呢?再看一下后面的left_child,right_child,发现是 8 7 -1 -1 4 1 2 5 这个来理解一下,应该是指8号节点,7号节点,-1代表的是NULL节点,也就是到头了,是叶子。 再来仔细看一下,发现出现的数字是:1 2 4 5 6 7 8,单单缺少了一个3! 为啥缺少3呢? 因为3不是任何人的left_child,right_child,它是根!!!!,这样的话,整个图就完整了! */ int n; string w[N]; int l[N], r[N], in[N]; int isleaf[N]; /* 8 * 8 7 a -1 -1 * 4 1 + 2 5 b -1 -1 d -1 -1 - -1 6 c -1 -1 (a+b)*(c*(-d)) */ string dfs(int u) { // 表达式树特点:叶子节点都是真实数字,非叶子节点都是操作符 string left, right; // if (isleaf[u]) return w[u]; // 递归终点,如果是叶子,本句话可以省略掉 // 这是因为isleaf[u]时,l[u]==-1 && r[u]==-1 ,则下面的两个分支都不会走,直接到了return那句,left,right都是空,还是返回w[u],一样的 if (l[u] != -1) { left = dfs(l[u]); // 递归左儿子, if (!isleaf[l[u]]) left = "(" + left + ")"; // 如果左儿子不是叶子,需要把表达式加上括号 } if (r[u] != -1) { // 右儿子不为空 right = dfs(r[u]); // 递归右儿子 if (!isleaf[r[u]]) right = "(" + right + ")"; // 如果右儿子不是叶子,需要把表达式加上括号 } // 返回中序遍历结果 return left + w[u] + right; } int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> w[i] >> l[i] >> r[i]; // data left_child right_child if (l[i] != -1) in[l[i]]++; // 记录入度 if (r[i] != -1) in[r[i]]++; // 记录入度 if (l[i] == -1 && r[i] == -1) isleaf[i] = 1; // 叶子 } // 找根 int root; for (root = 1; root <= n; root++) if (!in[root]) break; // 入度为零的是根 // 通过中序遍历,构建中缀表达式 cout << dfs(root) << endl; return 0; }