根据表达式序列(前缀、中缀、后缀)构建表达式树

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

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

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

 

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
为了回答你的问题,我将介绍前缀中缀后缀表达式,并展示如何在它们之间进行转换。 1. 前缀表达式(也称为波兰式): 在前缀表达式中,运算符位于操作数之前。例如,表达式 "2 + 3" 的前缀形式为 "+ 2 3"。 2. 中缀表达式中缀表达式是我们通常使用的常规数学表达式形式。它使用括号和运算符的优先级来表示运算顺序。例如,表达式 "2 + 3" 就是一个中缀表达式。 3. 后缀表达式(也称为逆波兰式): 在后缀表达式中,运算符位于相应的操作数之后。例如,表达式 "2 + 3" 的后缀形式为 "2 3 +"。 现在,我将向你展示如何将中缀表达式转换为前缀后缀表达式。 从中缀前缀转换: 1. 反转中缀表达式。 2. 将反转的中缀表达式转换为后缀形式。 3. 反转后缀表达式即可得到前缀表达式。 从中缀后缀转换: 1. 创建一个空栈和一个空输出列表。 2. 从左到右扫描中缀表达式的每个符号。 - 如果遇到操作数,将其添加到输出列表。 - 如果遇到运算符,将其压入栈中。 - 如果遇到左括号,将其压入栈中。 - 如果遇到右括号,则连续弹出栈顶元素并将其添加到输出列表,直到遇到左括号为止。注意:左括号不会被添加到输出列表中。 如果栈顶元素是左括号,则将其弹出栈。 - 如果遇到的运算符具有比栈顶运算符更高的优先级,将其压入栈中。 如果遇到的运算符具有与栈顶运算符相同的优先级,并且是左结合的运算符,则将栈顶运算符弹出并添加到输出列表中,然后将当前运算符压入栈中。 如果遇到的运算符具有与栈顶运算符相同的优先级,并且是右结合的运算符,则将当前运算符压入栈中。 - 重复步骤2直到扫描完整个中缀表达式。 3. 将栈中剩余的所有运算符弹出并添加到输出列表中。 4. 输出列表即为转换后的后缀表达式。 希望这个解释对你有帮助!如果你有其他问题,可以继续问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值