二叉树是表达式处理的常用工具。找到"最后计算"的运算符(它是整棵表达式树的根),然后递归处理。
递归处理成树是表达式处理的一个重要方式。这里我只记录和理解了lrjlrjlrj老师的代码(抄了一遍,自己还没动手自己写过。不过目前这不是重点内容,所以到此为止。
个位数加减乘除成表达式树
const int maxn = 1000;
int lch[maxn],rch[maxn];char op[maxn];
int nc=0;
int build_tree(char* s,int x,int y){
int i,c1=-1,c2=-1,p=0;
int u;
if(y-x==1){
u=++nc;
lch[u]=rch[u]=0;op[u]=s[x];
return u;
}
for(int i=x;i<y;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);//找不到其他符号:整个表达式被一对括号括起来
u=++nc;
lch[u]=build_tree(s,x,c1);
rch[u]=build_tree(s,c1+1,y);
op[u]=s[c1];
return u;
}
引入一道例题,UVa12219UVa12219UVa12219
对于一棵二叉树(字符串作为节点)的括号表达式,你需要简化这个表达式,使得相同子树返回子树编号。
这里采用递归建树,用mapmapmap记录子树编号,如果存在就使得新建子树编号减一。
最后递归输出。lrjlrjlrj老师真的tqltqltql
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<cctype>
#include<string>
#include<cmath>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
#define eps 1e-6
const int maxn = 60000;
int T,kase,cnt;
char expr[maxn*5],*p;//用于遍历
int done[maxn];//结点是否已经输出
struct Node{
string s;
int hash,left,right;
bool operator < (const Node& rhs) const{
if(hash!=rhs.hash)return hash < rhs.hash;
if(left!=rhs.left)return left < rhs.left;
return right<rhs.right;
}
}node[maxn];
map<Node,int>dict;
int parse(){
int id = cnt++;//第几棵子树(相同的话后面会-1
Node& u = node[id];//对于新树如果是原来的子树,下次创新的时候用的还是这个cnt(后面-1了)
u.left=u.right=-1;
u.s="";
u.hash=0;
while(isalpha(*p)){
u.hash=u.hash*27+*p-'a'+1;//27进制哈希
u.s.push_back(*p);
p++;
}
if(*p=='('){
p++;u.left=parse();p++;u.right=parse();p++;
}//递归处理括号内容,注意左右括号和中间的逗号要跳过
if(dict.count(u)!=0){
id--;cnt--;
return dict[u];//返回:map上的对应子树结点
}
return dict[u] = id;//未重复。
}
void print(int v){
if(done[v] == kase){
printf("%d",v+1);
}
else{
done[v]=kase;
printf("%s",node[v].s.c_str());
if(node[v].left!=-1){
putchar('(');
print(node[v].left);
putchar(',');
print(node[v].right);
putchar(')');
}
}
}
int main(){
scanf("%d",&T);
for(kase = 1;kase <= T;kase ++){
dict.clear();
cnt = 0;
scanf("%s",expr);
p = expr;
print(parse());
putchar('\n');
}
return 0;
}