中缀表达式——表达式树

本文介绍了如何将中缀表达式转化为表达式树,强调了叶节点为数字以及运算符优先级在树结构中的体现。通过分析括号内外运算符的优先级关系,提出了构建树结构的方法,并提供了相关代码实现。

中缀表达式——表达式树

还记得之前讲过的波兰表达式和逆波兰表达式么?我再最后提了一句可以将中缀表达式像以下的方法解析成一个树:

在这里插入图片描述
波兰和逆波兰表达式分别是对上面得树进行前序和后序遍历。我们这里的表达式树,就是这个树。我们现在需要学习如何将中缀表达式转化为上面这个树。


代码实现

事实上我们可以简单的总结几个小结论:

1.叶节点一定是数字
2.没有括号的情况下,相对运算优先级低的运算符放在树的上层位置

根据上面的两个结论,我们对建树就有一个粗略的概念了,用l和r分别表示两个端点[l,r),如果r-l=1,代表表达式由一个结点组成,如果表达式合法,那么剩下的一定是一个数字,于是构造成叶节点。

对于一长段的表达式,我们需要遍历一遍找到合适的运算符作为根节点。但现在的问题如何处理括号改变运算优先级的情况。

事实上我们再深入观察一下可以发现,如果一个表达式括号外有运算符,那么括号外的运算符的优先级一定可以视为低于括号内的运算符。也就是说作为根节点的运算符,一定要在括号之外。

如果不存在这样的结点呢?说明整个表达式都在括号之内,脱去外层的括号即可。代码如下:

const int maxn=1000;//nc表示当前树里面的结点总数,lch[i]和rch[i]表示编号为i的结点左右子节点的编号 
int lch[maxn],rch[maxn],nc=0; char op[maxn];//op[i]表示编号为i的结点存储的字符 
int build_tree(char* s,int l,int r){//l和r分别表示遍历表达式某段区间的左右端点:[x,y) 
	int i,c1=-1,c2=-1,p=0;//p用于记录当前表达式出现的括号数,左括号+1,右括号-1
	//p=0代表在括号外,p不等于0代表在括号内
	//当我们寻找根节点时,我们优先需要寻找的是括号外的运算符作为根节点
	//c1表示括号外最后出现的"+-"运算符,c2表示括号外最后出现的"*/"运算符
	//因为对于一个表达式,没有括号下两种运算符的优先级是不同的
	//加减后运算所以应当放在较为上层的位置
	if (r-l==1){nc++; lch[u]=rch[u]=0; op[u]=s[l]; return nc;} 
	//当区间内仅一个字符,那么它显然为一个叶节点,当前的结点个数作为它的编号
	//由于是叶结点,叶节点没有左右子节点,lch和rch的值设置为0  
	for (int i=l;i<r;i++){//将表达式的字符遍历一编,寻找括号外的运算符 
		switch(s[i]){ 
			case'(':p++; break;
			case')':p--; break;
			case'+':case'-':if(!p)c1=i; break;
			case'*':case'/':if(!p)c2=i; break;
		}
	} if (c1<0) c1=c2;//找不到括号外的加减号,再用优先级比较高的乘除号
	if (c1<0) return build_tree(s,x+1,y-1);//整个表达式被一对括号括起来了 
	//以c1作为根节点递归遍历左子树和右子树 
	nc++; lch[nc]=build_tree(s,l,c1); rch[nc]=build_tree(s,c1+1,r);
	op[nc]=s[c1]; return nc;
}

事实上我怀疑会不会转化成前缀表达式,之后做起来思路上更加清晰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值