​PAT 1130​​​ ​​C++​​版

1.题意


Given a syntax tree (binary), you are supposed to output the corresponding infix expression, with parentheses reflecting the precedences of the operators.


给出一个二叉语法树,你需要求出该二叉树对应的中缀表达式,使用括号反映操作符的优先权。

2.分析


  • 建树
  • 找出根节点
  • 使用中序遍历输出中缀表达式
  • 对于根节点和叶子节点不输出​​()​【这个认识对于解决这道题是决定性的】

3.代码

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

struct node{
char data[15];//根节点的值 ,是一个符号
int leftChi,rightChi;//左右孩子的节点
};

int N;//二叉树的节点数
int array[22];//用于求出根节点
node n[22];

//中序遍历 得到中缀表达式
void ldr(int root){
if(n[root].leftChi!=-1 || n[root].rightChi!=-1)
cout << "(";
if(n[root].leftChi!=-1){//如果存在左孩子
ldr(n[root].leftChi);
}
cout << n[root].data ;
if(n[root].rightChi!=-1){
ldr(n[root].rightChi);
}
if(n[root].leftChi!=-1 || n[root].rightChi !=-1 )
cout << ")";
}

//找根节点
int lookRoot(){
int i ;
for(i = 1;i<= N;i++){
if(array[i] == 0) break;//说明是根节点
}
return i;
}

int main(){
scanf("%d",&N);
int i ;
memset(array,0,sizeof(array));//初始化为0
for(i = 1;i <= N;i++){
getchar();
scanf("%s %d %d",&n[i].data, &n[i].leftChi, &n[i].rightChi);
if(n[i].leftChi != -1) array[n[i].leftChi] = 1;
if(n[i].rightChi != -1) array[n[i].rightChi] = 1;
}
int root;
root = lookRoot();
int leftRoot ,rightRoot;
leftRoot = n[root].leftChi;
rightRoot = n[root].rightChi;

if(leftRoot != -1) ldr(leftRoot);
cout<<n[root].data;
if(rightRoot !=-1) ldr(rightRoot);
}

  • ​if(n[root].leftChi!=-1 || n[root].rightChi!=-1){...}​​​ 只有存在左孩子或者右孩子,就应该输出​​()​​。
  • 进行中序遍历的时候,注意​​if(leftRoot != -1) ldr(leftRoot);​​,如果不判断,直接中序遍历,则会出现段错误。
  • 注意输出​​(​​​或者​​)​​的顺序。

4.测试用例

3
- 3 2
a -1 -1
b -1 -1

1
a -1 -1

3
- 2 3
a -1 -1
b -1 -1

8
* 8 7
a -1 -1
* 4 1
+ 2 5
b -1 -1
d -1 -1
- -1 6
c -1 -1

5.执行结果

PAT 1130 C++版_#include

6.总结

  • 对于这种递归遍历的题,一定要有全局的思想。

7.其它解法

7.1 思想

思想是:对于是操作符,我们可以输出​​()​​,但是如果不是操作符,则直接输出即可。于是有如下的代码:

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

struct node{
char data[15];//根节点的值 ,是一个符号
int leftChi,rightChi;//左右孩子的节点
};

int N;//二叉树的节点数
int array[22];//用于求出根节点
node n[22];

//中序遍历 得到中缀表达式
void ldr(int root){
if( strcmp(n[root].data,"+") == 0||
strcmp(n[root].data,"-") == 0||
strcmp(n[root].data,"*") == 0||
strcmp(n[root].data,"/") == 0||
strcmp(n[root].data,"%") == 0||
strcmp(n[root].data,"&") == 0)
cout << "(";
if(n[root].leftChi!=-1){//如果存在左孩子
ldr(n[root].leftChi);
}
cout << n[root].data ;
if(n[root].rightChi!=-1){
ldr(n[root].rightChi);
}

if( strcmp(n[root].data,"+") == 0||
strcmp(n[root].data,"-") == 0||
strcmp(n[root].data,"*") == 0||
strcmp(n[root].data,"/") == 0||
strcmp(n[root].data,"%") == 0||
strcmp(n[root].data,"&") == 0)
cout << ")";
}

//找根节点
int lookRoot(){
int i ;
for(i = 1;i<= N;i++){
if(array[i] == 0) break;//说明是根节点
}
return i;
}

int main(){
scanf("%d",&N);
int i ;
memset(array,0,sizeof(array));//初始化为0
for(i = 1;i <= N;i++){
getchar();
scanf("%s %d %d",&n[i].data, &n[i].leftChi, &n[i].rightChi);
if(n[i].leftChi != -1) array[n[i].leftChi] = 1;
if(n[i].rightChi != -1) array[n[i].rightChi] = 1;
}
int root;
root = lookRoot();
//cout<<"root = "<<root<<endl;
int leftRoot ,rightRoot;
leftRoot = n[root].leftChi;
rightRoot = n[root].rightChi;

if(leftRoot != -1) ldr(leftRoot);
cout<<n[root].data;
if(rightRoot !=-1) ldr(rightRoot);
}

但是上述代码存在的问题是:你并不知道题目中操作符的定义,所以有可能远不止​​+,-,*,/,%​​这几个操作符。所以导致有测试用例出错。