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++版_c

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);
}

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