利用二叉树求表达式的值,首先要注意表达式中先乘除后加减的运算顺序,所以在建立树的过程中,就要将加减尽量作为根节点,最后一个加减号作为根节点。建完树之后是运算过程,采用树的后序遍历来运算。
二叉树的节点结构,其中值的类型用char型
struct node { char data; node* left; node* right; };
node *CRTree(char s[],int begin,int end) { node *p; int k,plus=0,posi; if (begin==end) //只有一个字符,构造的是一个叶子节点 { p=(node *)malloc(sizeof(node)); //分配存储空间 p->data=s[begin]; //值为s[begin] p->left=NULL; p->right=NULL; return p; } //以下为begin!=end的情况 for (k=begin; k<=end; k++) if (s[k]=='+' || s[k]=='-') { plus++; posi=k; //最后一个+或-的位置 } if (plus==0) //没有+或-的情况(因为若有+、-,前面必会执行plus++) for (k=begin; k<=end; k++) if (s[k]=='*' || s[k]=='/') { plus++; posi=k; } //以上的处理考虑了优先将+、-放到二叉树较高的层次上 //由于将来计算时,运用的是后序遍历的思路 //处于较低层的乘除会优先运算 //从而体现了“先乘除后加减”的运算法则 //创建一个分支节点,用检测到的运算符作为节点值 if (plus!=0) { p=(node *)malloc(sizeof(node)); p->data=s[posi]; //节点值是s[posi] p->left=CRTree(s,begin,posi-1); //左子树由s[begin]至s[posi-1]构成 p->right=CRTree(s,posi+1,end); //右子树由s[posi+1]到s[end]构成 return p; } else //若没有任何运算符,返回NULL return NULL; }
下面是运算过程
double Comp(node *b) { double v1,v2; if (b==NULL) return 0; if (b->left==NULL && b->right==NULL) //叶子节点,应该是一个数字字符(本项目未考虑非法表达式) return b->data-'0'; //叶子节点直接返回节点值,结点中保存的数字用的是字符形式,所以要-'0' v1=Comp(b->left); //先计算左子树 v2=Comp(b->right); //再计算右子树 switch(b->data) //将左、右子树运算的结果再进行运算,运用的是后序遍历的思路 { case '+': return v1+v2; case '-': return v1-v2; case '*': return v1*v2; case '/': if (v2!=0) return v1/v2; else abort(); } }
最后要记得将新建的二叉树销毁
void DestroyBTNode(node *&b) //销毁二叉树 { if (b!=NULL) { DestroyBTNode(b->left); DestroyBTNode(b->right); free(b); } }