根据表达式序列(前缀、中缀、后缀)构建表达式树
如果输入序列是表达式(前缀表达式、中缀表达式、后缀表达式,中缀表达式要求带括号有几个运算符就带几个)则构建出来的树为表达式树,对该树前、中、后序遍历得到对应序的表达式。
不过,中缀表达式带括号,而表达式树不带括号,故中序遍历表达式树时需要加适当的括号才能得到正确的中缀表达式。
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个运算符入栈有卡特兰数种出栈顺序,相关题:LeetCode241)
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 else 20 { 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 else 22 {//操作符 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<stdio.h> 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 100 26 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 else 55 { 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、前后缀表达式的计算
前缀表达式:从后往前扫,遇到操作数入栈、遇到字符时取两栈顶元素进行相应运算后结果入栈。
后缀表达式:与上类似,只是是从前往后扫。
相关阅读:二叉树-MarchOn
转载于:https://www.cnblogs.com/z-sm/p/6807308.html
根据表达式序列(前缀、中缀、后缀)构建表达式树相关推荐
- 中缀表达式转换为前缀及后缀表达式并求值【摘】
它们都是对表达式的记法,因此也被称为前缀记法.中缀记法和后缀记法.它们之间的区别在于运算符相对与操作数的位置不同:前缀表达式的运算符位于与其相关的操作数之前:中缀和后缀同理. 举例: (3 + 4) ...
- C#数据结构-前缀中缀后缀+中缀转后缀
目录 一.前缀中缀后缀表达式 1.中缀表达式 2.前缀表达式 3.后缀表达式 二.中缀转后缀 一.前缀中缀后缀表达式 1.中缀表达式 中缀表达式就是平常生活中计算式子的写法,例如:(3+4)*5-6 ...
- 前缀 中缀 后缀表达式2
对于未经训练的用户来说,计算机科学领域中数学表达式求值的传统方法即不顺手又难以使用:软件工程师 Nikola.Stepan 旨在改变这些传统方法.他的 applet W3Eval 对表达式求值与您用纸 ...
- python【数据结构与算法】表达式(前缀中缀后缀表达式)与Two fork tree
文章目录 1 相关概念 2 与二叉树关系 3 表达式转换 4 另一种方法 1 相关概念 前缀表达式(Prefix Notation)是指将运算符写在前面操作数写在后面的不包含括号的表达式,而且为了纪念 ...
- 数据结构:前缀,中缀,后缀表达式(逆波兰表达式)
前缀表达式(波兰表达式) 前缀表达式的运算符位于操作数之前. 比如 (1+2)*3-4 对应的前缀表达式就是: - * + 1 2 3 4 前缀表达式的计算机求值 从右至左扫描表达式,遇到数字时,就 ...
- 前缀中缀后缀表达式的计算求值
原文在这里 表达式 前缀表达式(波兰表达式) 前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前 举例说明: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6 前缀表达式求值 ...
- 表达式树前缀中缀后缀表达式
表达式树( expression tree ), 表达式树的树叶是操作数( operand ),比如常数或变量,而其他的节点为操作符( operator )如: 由于这里所有的操作都是二元的,因此这棵 ...
- 前缀中缀后缀表达式介绍
一 前缀表达式 1 前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前. 2 举例 (3+4)×5-6 对应的前缀表达式是: - × + 3 4 5 6 3 前缀表达式的计算机求值过程 从右至左扫 ...
- 中缀表达式转换为前缀或后缀表达式的手工做法
以 a/b + ( c*d - e*f) / g 为例: 步骤1:按照运算符的优先级对所有的运算单元加括号. ((a/b) + (( (c*d) - (e*f)) / g)) 步骤2:转换为前缀或后缀 ...
- 前缀 中缀 后缀表达式
1.前缀表达式叫波兰式,后缀叫逆波兰式 2.中缀表达式转另外两个比较简单,前后缀装中缀较麻烦 3.问题分求表达式还是求值,如果是求值则需要两个栈,一个是操作符栈,一个是操作数栈,等操作符栈入栈完毕后依 ...
最新文章
- 初中计算机指导教师意见,初中信息技术教学计划(推荐3篇)
- 如何在多Node版本的情况下公用一个npm
- 101PPT游戏化换肤遇到的问题
- ASP.NET服务器端控件原理分析
- OpenCV摄像机videocapture camera的实例(附完整代码)
- php html asp .net iis tomcat,iis+apache+tomcat 整合共享80口 支持ASP .NET JSP PHP全能WEB服务...
- 怎么查看MySQL 源码编译了什么_Mysql 源码编译教程贴
- SLAM方向公众号、知乎、博客学习参考
- Myeclipse 2020.5 版本首发!支持 Java14
- 什么是数据建模_数据建模是什么意思
- matlab猜数字游戏程序,matlab 猜数字小游戏
- 更新计算机策略命令,组策略更新命令
- 【005】基于Vue.js及相关插件的仿微博移动版的单页应用(SPA)项目(含源码、运行教程)
- 探究斐波那契数列的通项公式
- OpenSSL/GmSSL 动态引擎
- 如何生成26个英文字母
- python实现用户登录注册界面_实现前后端登录注册界面
- 7-14 电话聊天狂人(25 分)
- cassandra安装及配置
- android开发获取签名错误,android开发打包签名出现-failed to export application的解决思路...
热门文章
- 什么是域名系统或 DNS?
- linux清理垃圾文件,安装及使用Sweeper从Linux系统上清除垃圾文件
- 计算机驱动器程序,打开计算机CD驱动器的位置
- 计算机黑屏时间,电脑开机黑屏时间长怎么办?Win10开机黑屏时间很久的解决方法...
- element -ui如何去掉原来的蓝色下划线
- 宿命论与非宿命论新解
- uva11045(最大二分图匹配)
- iosepub阅读器_epub格式电子书阅读器 iOS版
- ubuntu20.04 命令行下,复制与粘贴快捷键分别是ctrl+shift+c、 ctrl+shift+v
- python统计三国演义人物出场次数