博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
根据表达式序列(前缀、中缀、后缀)构建表达式树
阅读量:4621 次
发布时间:2019-06-09

本文共 6605 字,大约阅读时间需要 22 分钟。

如果输入序列是表达式(前缀表达式、中缀表达式、后缀表达式,中缀表达式要求带括号有几个运算符就带几个)则构建出来的树为表达式树,对该树前、中、后序遍历得到对应序的表达式。

不过,中缀表达式带括号,而表达式树不带括号,故中序遍历表达式树时需要加适当的括号才能得到正确的中缀表达式。

1、表达式树的构建与遍历

0、工具函数(链表节点定义、读取下一个字符、判断字符是否操作数):

1 typedef struct node 2 { 3     char data; 4     struct node * lchild; 5     struct node * rchild; 6 }BTNode,*BTREE; 7  8  9 char nextToken(char infix[])//括号、操作数、操作符等 都为一个字符 10 {11     static int pos=0;12     while(infix[pos]!='\0' && infix[pos]==' '){pos++;}//跳过空格 13     return infix[pos++];14 }15 int isOpNum(char ch)//是否是操作数 16 {17     if(ch=='#' || ch=='(' || ch==')' || ch=='+' || ch=='-' || ch=='*' || ch=='/' || ch==' ' || ch=='|' )18     {19         return 0;20     }21     return 1;22 }
View Code

1、输入前缀表达式构建表达式树(递归):

1 void createPrefix_recursive(char prefix[],BTREE &T) 2 {
//递归方式_由前缀表达式构建表达式树 3 char x=nextToken(prefix); 4 5 T=(BTREE)malloc(sizeof(BTNode)); 6 T->data=x; 7 T->lchild=NULL; 8 T->rchild=NULL; 9 10 if(!isOpNum(x))//是操作符。前缀表达式的最后一个字符一定是操作数,所以下面的递归会停止。 11 { 12 createPrefix_recursive(prefix,T->lchild);13 createPrefix_recursive(prefix,T->rchild);14 }15 }
View Code

2、输入中缀表达式构建表达式树(递归):

(要求输入的中缀表达式带括号,有n个运算符就有n个括号,为什么?因为加括号就是为了给运算符定优先级。进一步的,若给不带括号的中缀表达式加括号有几种?卡特兰数种,因为n个运算符入栈有卡特兰数种出栈顺序,相关题:)

1 void createInfix_recursive(char infix[],BTREE &T) 2 {
//递归方式_由中缀表达式构建表达式树,要求输入的中缀表达式加括号,有几个操作数就几个括号 。如果输入的前、中、后缀表达式都带括号,则很容易由此法改造得到构建表达式树的算法。 3 char x=nextToken(infix); 4 5 T=(BTREE)malloc(sizeof(BTNode)); 6 T->lchild=NULL; 7 T->rchild=NULL; 8 9 if(x=='(')10 {
//处理括号里的表达式 11 createInfix_recursive(infix,T->lchild);//表达式的左操作数 12 13 x=nextToken(infix);//表达式的操作符 14 T->data=x;15 16 createInfix_recursive(infix,T->rchild);//表达式的右操作数 17 nextToken(infix);//右括号 18 }19 else20 {21 T->data=x;22 }23 }
View Code

3、输入后缀表达式构建表达式树(非递归)

1 #define M 100 2 void createPostfix_nonrecursive(char postfix[],BTREE &T) 3 {
//非递归方式_由后缀表达式构建表达式树 4 BTREE stack[M],p; 5 int top=-1; 6 char x; 7 while(1) 8 { 9 x=nextToken(postfix);10 if(x=='\0') return;11 12 p=(BTREE)malloc(sizeof(BTNode)) ;13 p->data=x;14 p->lchild=NULL;15 p->rchild=NULL;16 17 if(isOpNum(x))18 {
//操作数 19 stack[++top]=p;20 }21 else22 {
//操作符 23 p->lchild=stack[top-1];24 p->rchild=stack[top];25 stack[top-1]=p;26 top--;27 T=p;28 }29 }30 T=stack[0];31 }
View Code

4、表达式树遍历(递归,前缀、中缀、后缀):(中缀遍历在遍历时需要加括号才能得到正确结果,方法为访问到内部节点时加左右括号。)

1 void searchPrefix(BTREE T) 2 { 3     if(T!=NULL) 4     {
//·ÃÎʵ½ÄÚ²¿½Úµãʱ×óÓÒ¼ÓÀ¨ºÅ 5 // if(T->lchild!=NULL && T->rchild!=NULL){ printf("("); } 6 7 printf("%c",T->data); 8 searchPrefix(T->lchild); 9 searchPrefix(T->rchild);10 11 // if(T->lchild!=NULL && T->rchild!=NULL){ printf(")"); }12 }13 }14 void searchInfix(BTREE T)15 {16 if(T!=NULL)17 {
//ÖÐÐò±éÀú±í´ïʽÊ÷ÐèÒªÌí¼ÓÀ¨ºÅÐÅÏ¢£¬ÒÔ±£Ö¤ÔËËãÓÅÏȼ¶£º·ÃÎʵ½ÄÚ²¿½Úµãʱ×óÓÒ¼ÓÀ¨ºÅ 18 if(T->lchild!=NULL && T->rchild!=NULL){ printf("("); }19 20 searchInfix(T->lchild);21 printf("%c",T->data);22 searchInfix(T->rchild);23 24 if(T->lchild!=NULL && T->rchild!=NULL){ printf(")"); }25 }26 }27 void searchPostfix(BTREE T)28 {29 if(T!=NULL)30 {
//·ÃÎʵ½ÄÚ²¿½Úµãʱ×óÓÒ¼ÓÀ¨ºÅ 31 // if(T->lchild!=NULL && T->rchild!=NULL){ printf("("); }32 33 searchPostfix(T->lchild);34 searchPostfix(T->rchild);35 printf("%c",T->data);36 37 // if(T->lchild!=NULL && T->rchild!=NULL){ printf(")"); }38 }39 }
View Code

如果遍历前缀、后缀表达式时也要加括号,则方法一样,在访问到内部节点时加左右括号即可。从这里我们受到启发,不借助程序,手动将中缀表达式转换为前后缀表达式的方法:把括号内的操作符放到括号前面或后面然后去掉括号即可;反之,要将前后缀表达式转为中缀表达式,只要加上括号然后把操作符放到括号内两操作数中间即可!

5、测试:

1 int main() 2 {  3 //    *+A/-BCDE 4 //    ((A+((B-C)/D))*E) 5 //    ABC-D/+E* 6     char str[]="ABC-D/+E*"; 7     BTREE T; 8      9 //    createPrefix_recursive(str,T);10 //    createInfix_recursive(str,T);11     createPostfix_nonrecursive(str,T);12 13     14     searchPrefix(T);      15     printf("\n");16     17     searchInfix(T);18     printf("\n");19     20     searchPostfix(T);21     printf("\n");22     23     return 0;24 }
View Code

2、前中后缀表达式间的转换(以中缀表达式转后缀表达式为例)

// *+A/-BCDE

// ((A+((B-C)/D))*E)
// ABC-D/+E*

2.1、转换方法

手动转换:把括号内的操作符放到括号前面或后面然后去掉括号即可;反之,要将前后缀表达式转为中缀表达式,只要加上括号然后把操作符放到括号内两操作数中间即可!

程序转换:

法1:由中缀表达式构建表达式树,然后后序遍历该表达式树即可

法2:不借助表达式树,通过定义操作符的优先级纯借助栈来实现,如下:

1 #include
2 char nextToken(char infix[])//括号、操作数、操作符等 都为一个字符 3 { 4 static int pos=0; 5 while(infix[pos]!='\0' && infix[pos]==' '){pos++;}//跳过空格 6 return infix[pos++]; 7 } 8 int isOpNum(char ch)//是否是操作数 9 {10 if(ch=='#' || ch=='(' || ch==')' || ch=='+' || ch=='-' || ch=='*' || ch=='/' || ch==' ')11 {12 return 0;13 }14 return 1;15 }16 int isCurchPriorToChtop(char chCur,char chTop)//当前元素是否比栈顶元素优先级大 17 {18 if(chCur=='(' || chTop=='#' || chTop=='(') return 1;19 else if( (chCur=='*'||chCur=='/') && chTop!='*' && chTop!='/' ) return 1;20 else return 0;21 }22 23 //输入中缀表达式转后缀,单纯用堆栈。假定中缀表达式符合语法。操作数或操作符都为一个char,可能有空格 24 //也可通过对输入的中缀表达式构建表达式树然后后序遍历来得到后缀表达式。 25 #define M 10026 void infix2Postfix(char infix[])27 {28 char stack[M],x;29 int top=-1;30 stack[++top]='#';31 while(1)32 {33 x=nextToken(infix);34 if(isOpNum(x))35 {36 printf("%c",x);37 }38 else if(x=='#')39 {
//中缀表达式扫描结束 40 while(top>=0)41 {42 printf("%c",stack[top--]);43 }44 return;45 }46 else if(x==')')47 {48 while(stack[top]!='(')49 {50 printf("%c",stack[top--]);51 }52 top--;53 }54 else55 {56 while(!isCurchPriorToChtop(x,stack[top]))57 {58 printf("%c",stack[top--]);59 }60 stack[++top]=x;61 }62 }63 }64 int main()65 {66 char infix[]="(((A+(B-C)/D) *E)) #";67 int n=sizeof(infix)/sizeof(char);68 infix2Postfix(infix);69 return 0;70 }
View Code

2.2、转换相关的性质

中缀表达式转前后缀表达式后,操作数顺序不变、操作符顺序会改变,但前后缀表达式的操作符顺序恰好相反

2.3、前后缀表达式的计算

前缀表达式:从后往前扫,遇到操作数入栈、遇到字符时取两栈顶元素进行相应运算后结果入栈。

后缀表达式:与上类似,只是是从前往后扫。

 

相关阅读:

 

转载于:https://www.cnblogs.com/z-sm/p/6807308.html

你可能感兴趣的文章
GitHub笔记(三)——分支管理和多人协作
查看>>
Shell.xaml
查看>>
connection reset by peer, socket write error问题排查
查看>>
【luogu P4113 [HEOI2012]采花】 假题解
查看>>
第N次从零开始学Java笔记及思考_第一部分_基本语法(三)
查看>>
python里的Join函数
查看>>
log4j.properties 日志文件的详细配置说明
查看>>
Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制...
查看>>
nodejs使用案例-mysql操作
查看>>
JavaScript的闭包
查看>>
NuGet学习笔记(1) 初识NuGet及快速安装使用
查看>>
js实现的几种继承方式
查看>>
javascript飞机大战-----002游戏引擎
查看>>
ajax的访问 WebService 的方法
查看>>
微信内置浏览器如何自动跳转其它浏览器
查看>>
Some Posts about Tree for MVC
查看>>
小程序参数传递
查看>>
初始面向对象
查看>>
在Ubuntu上安装Intellij IDEA并创建桌面快捷方式
查看>>
Spring框架学习之第2节
查看>>