[数据结构与算法分析:C语言描述读书笔记]表达式树

中缀表达式转换与计算
本文介绍如何将中缀表达式转换为后缀表达式并进行计算,同时生成表达式树。涵盖负号处理、优先级设定及错误检查。

      对于表达式计算问题可以分成3部分,输入为中缀表达式,输出为:(1)后缀表达式;(2)计算结果;(3)表达式树,其中后面两个问题的求解依赖于前1个问题的求解。本文详细讨论了这三个问题。

1.后缀表达式的生成

读取中缀表达式,根据以下规则处理

(1)当字符不是操作符时,直接输入,否则进行优先级比较

(2)当栈为空时,将操作符直接压入

(3)当操作符为“(”时,直接压入

(4)当操作符为“)”时,依次弹出操作符,直到(为止,但(并不输出

(5)依次比较栈顶与当前操作符的优先级,如栈顶操作符优先级不比当前操作符低的话,则弹出,直到栈顶操作符优先级比当前操作符低或者栈为空为止,然后将当前操作符压入

(6)比较优先级时“(”是个意外,除非当前操作符为“)”,否则不弹出

(7)当读到输入末尾时,将栈内剩余操作符输出

 本文不仅讨论了双目运算符,讨论了单目运算符!-,若要添加其他操作符其方法是类似的,使用到的操作符的优先级顺序如下:

操作符优先级
(  )4
  !      -($在计算结果用来替换负号)3
  *      /2
  +      -1

 

2.根据后缀表达式计算表达式结果

读取后缀表达式,若不是操作符则压入栈中,若是操作符则从栈中弹出相应个数的数进行计算,并将结果压入栈中

注:本文还讨论了符号-与减号-混用的情况,如果-前面是操作符或者位于第1位,则说明是负号,将其替换成$

3.生成表达式树

生成表达式树的过程和计算表达式类似,不过不是将树压入栈中,而是将相应的节点压入栈中;也不是将结果压入栈中,而是将新的节点压入栈中

4.实现代码

  1 /**本文件用于研究表达式树,包括:1.由中缀表达式生成后缀表达式;2.计算后缀表达式
  2  * 3.由后缀表达式构造一棵表达式树;4。由后缀表达式生成中缀、前缀表达式
  3  * 
  4  */
  5 
  6 import java.util.*;
  7 
  8 public class Main {
  9 
 10     public static void main(String[] args) {
 11         // 输入中缀表达式,由0-9、+、-、*、/、!符号组成
 12         Scanner inSting=new Scanner(System.in);
 13         String middleExpression=inSting.nextLine();
 14         //中缀表达式转换为后缀表达式
 15         String behindExpression=middleExpToBehindExp(middleExpression);
 16         //计算后缀表达式
 17         double answer=calculateBehindExp(behindExpression);
 18         System.out.println("计算结果为:"+answer);
 19         //构造表达式树
 20         expTree temp=behindTreeToExpTree(behindExpression);
 21         System.out.println("其表达式树为:");
 22         temp.printExpTree(temp, 0);
 23     }
 24     static String middleExpToBehindExp(String middleExpression){
 25     /*中缀表达式转换为后缀表达式的规则
 26      * 1.如果是数字则直接输出,如果是操作符的话就入栈
 27      * 2.比较栈里面操作符之间的优先级,将优先级更高或者相等的输出
 28      * 3.遇到)前操作符(不弹出
 29      * 4.遇到(后弹出到)为止,但(与)都不输出
 30      * 5.弹出操作符后,将当期操作符弹出
 31      * 6.读到输入末尾时,将栈中元素全部弹出
 32      * 7.优先级设置如下,()4;! - 3;/*  2;+ - 1;
 33      */
 34         String behindExp="";
 35         Stack<String> helperStack=new Stack<String>();
 36         //添加一个程序处理负号和减号之间的关系,如果-号前是操作符,则认为是负号,将其替换为其他符号,如$,其优先级和其他单目运算符一样
 37         for(int i=0;i<middleExpression.length();i++)
 38         {
 39             //开头为-,说明是负号
 40             if(i==0&&middleExpression.charAt(0)=='-')
 41                 {middleExpression='$'+middleExpression.substring(1);continue;}
 42             if(middleExpression.charAt(i)=='-'&&!isNumber(middleExpression.charAt(i-1)))
 43                 middleExpression=middleExpression.substring(0, i)+'$'+middleExpression.substring(i+1);
 44         }
 45         System.out.println(middleExpression);
 46             
 47         for(int i=0;i<middleExpression.length();i++){
 48             char nowElement=middleExpression.charAt(i);
 49             //如果是不是操作符则直接输出
 50             if(isNumber(nowElement))
 51                 behindExp=behindExp+nowElement;
 52             else
 53             {
 54                 //栈为空,则直接将操作符压入
 55                 if(helperStack.isEmpty())
 56                     {helperStack.push(nowElement+"");continue;}
 57                 //如果为)则输出直到(为止
 58                 if(nowElement==')')
 59                 {
 60                     int temp=helperStack.search("(");
 61                     for(int j=0;j<temp-1;j++)
 62                         behindExp=behindExp+helperStack.pop();
 63                     helperStack.pop();
 64                     continue;
 65                 }
 66                 //判断优先级,输出直到栈内操作符优先级小于当前操作符
 67                 do{
 68                     String temp=helperStack.peek();
 69                     //(只有遇到)操作符时才弹出
 70                     if(temp.charAt(0)=='(')
 71                         break;
 72                     if(compareOperateSymbol(temp,nowElement+""))
 73                         {behindExp=behindExp+temp;helperStack.pop();}
 74                 }while(!helperStack.isEmpty()&&compareOperateSymbol(helperStack.peek(),nowElement+""));
 75                 //将当前操作符压入
 76                 helperStack.push(nowElement+"");
 77             }
 78         }
 79         //读到输入末尾,将栈中元素全部弹出
 80         if(!helperStack.isEmpty())
 81         {int temp=helperStack.size();
 82             for(int i=0;i<temp;i++)
 83                 behindExp=behindExp+helperStack.pop();}
 84         System.out.println(behindExp);
 85         return behindExp;
 86     }
 87     //判断是不是数字,如果是则返回true,否则返回false
 88     static boolean isNumber(char a)
 89     {
 90         if(a=='/'||a=='*'||a=='+'||a=='-'||a=='!'||a=='('||a==')'||a=='$')
 91             return false;
 92         else
 93             return true;
 94     }
 95     //比较两个操作符的优先级
 96     static boolean compareOperateSymbol(String a,String b){
 97         int temp1=0,temp2=0;
 98         switch(a.charAt(0)){
 99             case '(':
100                 temp1=4;break;
101             case ')':
102                 temp1=4;break;
103             case '!':
104                 temp1=3;break;
105             case '*':
106                 temp1=2;break;
107             case '/':
108                 temp1=2;break;
109             case '+':
110                 temp1=1;break;
111             case '-':
112                 temp1=1;break;    
113             case '$':
114                 temp1=3;break;        
115         }
116         switch(b.charAt(0)){
117         case '(':
118             temp2=4;break;
119         case ')':
120             temp2=4;break;
121         case '!':
122             temp2=3;break;
123         case '*':
124             temp2=2;break;
125         case '/':
126             temp2=2;break;
127         case '+':
128             temp2=1;break;
129         case '-':
130             temp2=1;break;        
131         case '$':
132             temp2=3;break;    
133         }
134         if(temp1>=temp2)
135             return true;
136         else
137             return false;
138     }
139     static double calculateBehindExp(String a){
140         //构造辅助栈
141         Stack<Double> helperStack=new Stack<Double>();
142         for(int i=0;i<a.length();i++)
143         {
144             //如果是数字则压入栈中
145             if(isNumber(a.charAt(i)))
146                 helperStack.push(Double.parseDouble(a.charAt(i)+""));
147             //判断表达式是否有问题
148             if(a.charAt(i)=='+'||a.charAt(i)=='-'||a.charAt(i)=='*'||a.charAt(i)=='/')
149                 if(helperStack.size()<2)
150                     {System.out.println("表达式有误1,请检查");return -1;}
151             if(a.charAt(i)=='$'||a.charAt(i)=='!')
152                 if(helperStack.size()<1)
153                     {System.out.println("表达式有误2,请检查");return -1;}
154             //如果是操作符则,弹出相应的几个数,进行计算,并将结果压入
155             if(a.charAt(i)=='+')
156             {double temp1=helperStack.pop();double temp2=helperStack.pop();
157             temp2=temp2+temp1;helperStack.push(temp2);
158             }
159             if(a.charAt(i)=='-')
160             {double temp1=helperStack.pop();double temp2=helperStack.pop();
161             temp2=temp2-temp1;helperStack.push(temp2);
162             }
163             if(a.charAt(i)=='*')
164             {double temp1=helperStack.pop();double temp2=helperStack.pop();
165             temp2=temp2*temp1;helperStack.push(temp2);
166             }
167             if(a.charAt(i)=='/')
168             {double temp1=helperStack.pop();double temp2=helperStack.pop();
169             temp2=temp2/temp1;helperStack.push(temp2);
170             }
171             if(a.charAt(i)=='!')
172             {double temp1=helperStack.pop();
173              int temp2=1;
174              for(int j=1;j<=temp1;j++)
175                  temp2=temp2*j;
176              helperStack.push((double)temp2);
177             }
178             if(a.charAt(i)=='$')
179             {double temp1=helperStack.pop();
180              helperStack.push(-temp1);
181              }
182         }
183         //计算完之后若栈中还存在多余1个数则报错
184         if(helperStack.size()>1)
185             {System.out.println("表达式有误3,请检查");return -1;}
186         return helperStack.pop();
187     }
188     static expTree behindTreeToExpTree(String a){
189         //生成表达式树的过程和计算过程是类似的
190         Stack<expTree> helperStack=new Stack<expTree>();
191         for(int i=0;i<a.length();i++)
192         {
193             //如果是数字则压入栈中
194             if(isNumber(a.charAt(i)))
195                 {expTree temp=new expTree(a.charAt(i));helperStack.push(temp);}
196             //判断表达式是否有问题
197             if(a.charAt(i)=='+'||a.charAt(i)=='-'||a.charAt(i)=='*'||a.charAt(i)=='/')
198                 if(helperStack.size()<2)
199                     {System.out.println("表达式有误1,请检查");return  null;}
200             if(a.charAt(i)=='$'||a.charAt(i)=='!')
201                 if(helperStack.size()<1)
202                     {System.out.println("表达式有误2,请检查");return null;}
203             //如果是操作符则,弹出相应的几个数,进行计算,并将结果压入
204             if(a.charAt(i)=='+'||a.charAt(i)=='-'||a.charAt(i)=='*'||a.charAt(i)=='/')
205             {expTree temp1=helperStack.pop();expTree temp2=helperStack.pop();
206             expTree temp3=new expTree(a.charAt(i),temp2,temp1);helperStack.push(temp3);
207             }
208             
209             if(a.charAt(i)=='!'||a.charAt(i)=='$')
210             {expTree temp1=helperStack.pop();
211              expTree temp2=new expTree(a.charAt(i),temp1,null);
212              helperStack.push(temp2);
213             }
214         }
215         //读完之后若栈中还存在多余1个数则报错
216         if(helperStack.size()>1)
217             {System.out.println("表达式有误3,请检查");return null;}
218         return helperStack.pop();
219     }
220 }
221 
222 //构造表达式类
223 class expTree{
224     char symbol;
225     expTree left;
226     expTree right;
227     expTree(){
228         
229     }
230     expTree(char temp){
231         symbol=temp;
232     }
233     expTree(char temp,expTree leftTree,expTree rightTree){
234         symbol=temp;
235         left=leftTree;
236         right=rightTree;
237     }
238     void printExpTree(expTree a,int width){
239         //如果a不为空,则循环遍历,前序打印
240         if(a!=null){
241             for(int i=0;i<width;i++)
242                 System.out.print('\t');
243             System.out.println(a.symbol);
244             printExpTree(a.left,width+1);
245             printExpTree(a.right,width+1);
246             
247         }
248     }
249 }

5.演示结果

注意输入阶乘符号!时,不要输成了感叹号!

 

转载于:https://www.cnblogs.com/guidepost/p/7009281.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值