1.用栈实现综合计算器(中缀)

  1 package Zhan;
  2 
  3 import java.util.Scanner;
  4 
  5 public class ComprehensiveCalculatorDemo {
  6     public static void main(String[] args){
  7         MyStack ns=new MyStack(20);//存放数字的栈
  8         MyStack os=new MyStack(20);//存放符号的栈
  9         int num1=0;
 10         int num2=0;
 11         int index=0;
 12         int res=0;
 13         int oper;
 14         char c=' ';
 15         String multibitNumber="";
 16         System.out.println("输入表达式:");
 17         Scanner s=new Scanner(System.in);
 18         String expersion=s.next();
 19         while(true){
 20             c=expersion.substring(index, index+1).charAt(0);
 21             if(os.isOperator(c)){
 22                 if(os.isEmpty()){
 23                     os.push(c);
 24                 }else{
 25                     if(os.priority(c)<os.priority(os.stack[os.top])){
 26                         os.push(c);
 27                     }else{
 28                         num1=ns.pop();
 29                         num2=ns.pop();
 30                         oper=os.pop();
 31                         res=os.canculateResult(num1, num2, oper);
 32                         ns.push(res);
 33                         os.push(c);
 34                         
 35                     }
 36                 }
 37             }else{
 38                 
 39                 multibitNumber+=c;
 40                 if(index==expersion.length()-1){
 41                     ns.push(Integer.parseInt(multibitNumber));
 42                 }else{
 43                     if(os.isOperator(expersion.substring(index+1, index+2).charAt(0))){
 44                         ns.push(Integer.parseInt(multibitNumber));
 45                         multibitNumber="";
 46                     }
 47                 //ns.push(c-48);//进行字符转数字并入数字栈(注意字符"1"和数字"1"的区别!!!)
 48                 }
 49             }
 50             index++;
 51             if(index>=expersion.length()){
 52                 break;
 53             }
 54         }
 55         
 56         while(true){
 57             if(os.isEmpty()){
 58                 break;
 59             }else{
 60                 num1=ns.pop();
 61                 num2=ns.pop();
 62                 oper=os.pop();
 63                 res=ns.canculateResult(num1, num2, oper);
 64                 ns.push(res);
 65             }
 66             
 67         }
 68         int result=ns.pop();
 69         System.out.println(expersion+"="+result);
 70     }
 71     
 72     
 73     
 74 }
 75 
 76 
 77 class MyStack{
 78     int maxSize;
 79     int stack[];
 80     int top=-1;
 81     
 82     public MyStack(int maxSize) {
 83         this.maxSize = maxSize;
 84         this.stack=new int[maxSize];
 85     }
 86     
 87     //判断栈是否为空
 88     public boolean isEmpty(){
 89         return top==-1;
 90     }
 91     
 92     
 93     
 94     //判断栈是否已满
 95     public boolean isFull(){
 96         return top==maxSize-1;
 97     }
 98     
 99     //入栈
100     public void push(int data){
101         if (isFull()){
102             System.out.println("栈已满!!!");
103         }else{
104             top++;
105             stack[top]=data;
106         }
107     }
108     
109     
110     
111     //出栈
112     public int pop(){
113         if(isEmpty()){
114             throw new RuntimeException("栈空!!!");
115         }else{
116             int temp=stack[top];
117             top--;
118             return temp;
119         }
120     }
121     
122     
123     
124     
125     
126     
127     //显示栈内数据
128     public void show(){
129         if(isEmpty()){
130             throw new RuntimeException("栈空!!!");
131         }else{
132             for(int i=top;i>-1;i--){
133                 System.out.println("stack["+i+"]----->"+stack[i]);
134             }
135         }
136     }
137     
138     
139     
140     
141     
142     
143     //设定运算符号的优先级,优先级越高,所对应的数字越小,从1开始
144     public int priority(int operator){
145         if(operator=='*'||operator=='/'){
146             return 0;
147         }else if(operator=='+'||operator=='-'){
148             return 1;
149         }else{
150             return -1;
151         }
152     }
153     
154     
155     
156     
157     
158     //判断是否为运算符
159     public boolean isOperator(int a){
160         if(a=='*'||a=='/'||a=='+'||a=='-'){
161             return true;
162         }else{
163             return false;
164         }
165     }
166     
167     
168     
169     
170     
171     //加、减、乘、除计算
172     public int canculateResult(int num1,int num2,int operator){
173         int result=0;
174         switch(operator){
175         case'*':
176             result=num2*num1;
177             break;
178         case'/':
179             result=num2/num1;
180             break;
181         case'+':
182             result=num2+num1;
183             break;
184         case'-':
185             result=num2-num1;
186             break;
187         default:
188             break;    
189         }
190         
191         return result;
192         
193     }
194     
195 }

结果:

存在问题:

最后一位数前的运算符号,将“+”当作"-",把“-”当作"+"

---------------------------------------------------------------------------------

这样反而没错

------------------------------------------------------------------------------------

  打印每一步运算结果,可以发现,问题出现在最后while循环的计算里面,计算是从栈顶开始的,表现在运算式中是从后向前计算,这时,每一个运算符号后面的式子会先计算,相当于加了(),如果这个运算符号是+,那么后面加不加()的没什么影响,如果这个运算符号是-。那么后面加上()的话就会导致计算出的结果和原式不同。

 

修改:添加以下代码

 

完整代码:

  1 package Zhan;
  2 
  3 import java.util.Scanner;
  4 
  5 public class ComprehensiveCalculatorDemo2 {
  6     
  7     public static void main(String[] args){
  8         
  9         MyStack2 ns=new MyStack2(20);
 10         MyStack2 os=new MyStack2(20);
 11         System.out.println("输入表达式:");
 12         Scanner scanner=new Scanner(System.in);
 13         String expersion=scanner.next();
 14         int num1=0;
 15         int num2=0;
 16         int res=0;
 17         int oper;
 18         int index=0;
 19         char c=' ';
 20         String multibitNumber="";
 21         
 22         //扫描表达式
 23         while(true){
 24             c=expersion.substring(index, index+1).charAt(0);//一位一位截取字符串,并将截取后的内容准换为char类型
 25             if(os.isOperator(c)){
 26                 if(os.isEmpty()){
 27                     os.push(c);
 28                 }else{
 29                 if(os.priority(c)<=os.priority(os.stack[os.top])){
 30                     num1=ns.pop();
 31                     num2=ns.pop();
 32                     oper=os.pop();
 33                     res=os.canculateResult(num1, num2, oper);
 34                     ns.push(res);
 35                     os.push(c);
 36                 }else{
 37                     os.push(c);
 38                 }
 39               }
 40             }else{
 41                 multibitNumber+=c;
 42                 if(index>=expersion.length()-1){
 43                     ns.push(Integer.parseInt(multibitNumber));
 44                 }else{
 45                     if(os.isOperator(expersion.subSequence(index+1, index+2).charAt(0))){//判断当前数字后面是否有数字,若有则进行拼接,再入栈,若没有则直接入栈
 46                         ns.push(Integer.parseInt(multibitNumber));
 47                         multibitNumber="";
 48                     }
 49                 }
 50             }
 51             index++;
 52             if(index==expersion.length()){
 53                 break;
 54             }
 55         
 56     }
 57         
 58         
 59         //需要修改,使数栈和符号栈中的元素倒排
 60         /*
 61         while(true){
 62             if(os.isEmpty()){
 63                 break;
 64             }else{
 65                 num1=ns.pop();
 66                 num2=ns.pop();
 67                 oper=os.pop();
 68                 res=ns.canculateResult(num1, num2, oper);
 69                 ns.push(res);
 70             }
 71             
 72         }
 73         
 74         */
 75         int a;
 76         int b;
 77         MyStack2 ns1=new MyStack2(20);//定义一个新的数栈,将原数栈中的元素压入栈,实现元素倒排
 78         MyStack2 os1=new MyStack2(20);//定义一个新的符号栈,将原符号栈中的元素压入栈,实现元素倒排
 79         
 80         while(ns.top!=-1){
 81             a=ns.pop();
 82             ns1.push(a);
 83             
 84         }
 85         
 86         
 87         while(os.top!=-1){
 88             b=os.pop();
 89             os1.push(b);
 90         }
 91         
 92         //对新的数栈和符号栈进行之前的操作
 93         while(true){
 94             if(os1.isEmpty()){
 95                 break;
 96             }else{
 97                 num1=ns1.pop();
 98                 num2=ns1.pop();
 99                 oper=os1.pop();
100                 res=ns1.canculateResult(num2, num1, oper);//注意参数顺序,与上面的canculateResult()方法中的参数顺序不同!!!
101                 ns1.push(res);
102             }
103         }
104         
105         int result=ns1.pop();
106         System.out.println(expersion+"="+result);
107     
108 
109 
110   }
111  }
112 
113 
114 
115 
116 class MyStack2{
117     int maxSize;
118     int stack[];
119     int top=-1;
120     
121     public MyStack2(int maxSize) {
122         this.maxSize = maxSize;
123         this.stack=new int[maxSize];
124     }
125     
126     //判断栈是否为空
127     public boolean isEmpty(){
128         return top==-1;
129     }
130     
131     
132     
133     //判断栈是否已满
134     public boolean isFull(){
135         return top==maxSize-1;
136     }
137     
138     //入栈
139     public void push(int data){
140         if (isFull()){
141             System.out.println("栈已满!!!");
142         }else{
143             top++;
144             stack[top]=data;
145         }
146     }
147     
148     
149     
150     //出栈
151     public int pop(){
152         if(isEmpty()){
153             throw new RuntimeException("栈空!!!");
154         }else{
155             int temp=stack[top];
156             top--;
157             return temp;
158         }
159     }
160     
161     
162     
163     
164     
165     
166     //显示栈内数据
167     public void show(){
168         if(isEmpty()){
169             throw new RuntimeException("栈空!!!");
170         }else{
171             for(int i=top;i>-1;i--){
172                 System.out.println("stack["+i+"]----->"+stack[i]);
173             }
174         }
175     }
176     
177     
178     
179     
180     
181     
182     //设定运算符号的优先级,优先级越高,所对应的数字越大,从0开始
183     public int priority(int operator){
184          if(operator=='*'||operator=='/'){
185             return 1;
186         }else if(operator=='+'||operator=='-'){
187             return 0;
188         }else{
189             return -1;
190         }
191     }
192     
193     
194     
195     
196     
197     //判断是否为运算符
198     public boolean isOperator(int oper){
199         if(oper=='*'||oper=='/'||oper=='+'||oper=='-'){
200             return true;
201         }else{
202             return false;
203         }
204     }
205     
206     
207     
208     
209     
210     //加、减、乘、除计算
211     public int canculateResult(int num1,int num2,int operator){
212         int result=0;
213         switch(operator){
214         case'*':
215             result=num2*num1;
216             break;
217         case'/':
218             result=num2/num1;
219             break;
220         case'+':
221             result=num2+num1;
222             break;
223         case'-':
224             result=num2-num1;
225             break;
226         default:
227             break;    
228         }
229         return result;
230         
231     }
232     
233     
234     
235 }

运行结果:

正确!!!

2.中缀表达式转后缀表达式

2.1步骤

 2.2将String类型的中缀表达式分割,并将分割后的元素存入到链表中

 1 public static List<String>StringToList(String ex){
 2         List<String>ls=new ArrayList<String>();
 3         int i=0;
 4         String st;
 5         while(i<ex.length()){
 6             if((ex.charAt(i)<48)||(ex.charAt(i)>57)){//如果是符号,则直接添加
 7                 ls.add(ex.charAt(i)+"");
 8                 i++;
 9             }else{
10                 st="";
11                 //如果是数字,则需要考虑是否为多位数
12                 while((ex.charAt(i)>47&&ex.charAt(i)<58)&&(i<ex.length())){
13                     st=st+ex.charAt(i);
14                     i++;
15                 }
16                 
17                 ls.add(st);
18             }
19         }
20         return ls;
21     }

运行:

(1)输入:1+

结果:

(2)输入:1+1

结果:

出现越界报错!!!

问题出在:当i已经越界时,还要执行ex.charAt(i)>47&&ex.charAt(i)<58这一步判断,而此时i已经越界,无法取到ex.charAt(i)的值,所以会报错

修改:调整一下判断顺序即可,先进性越界判定,再进行值的范围判定

2.3中缀转后缀并计算结果的完整代码

  1 package Zhan;
  2 
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 import java.util.Scanner;
  6 import java.util.Stack;
  7 
  8 /*
  9  * 将中缀表达式转换为后缀表达式,并计算结果
 10  * 步骤:
 11  * 1.遇到数字,将其压入s2;
 12  * 2.遇到括号:
 13  * (1)若为(,则压入s1栈;
 14  * (2)否则若为),则在s1中寻找(,将()中的元素全部从s1中弹出,并一次压入s2栈
 15  * 3.遇到运算符
 16  * (1)若s1栈为空或者s1栈顶是(,则入s1栈;
 17  * (2)否则,若此符号的优先级大于s1栈顶符号的优先级,则将此符号压入s1栈;
 18  * (3)否则,如此符号的优先级小于等于s1栈顶符号优先级,则将此时s1栈顶的符号弹出并压入s2栈,然后再回到第(1)步进行判断,并执行相应的程序,一直循环,直到s1为空为止
 19  */
 20 public class CalculateDemo {
 21     public static void main(String[] args){
 22         while(true){
 23         System.out.println("输入表达式:");
 24         Scanner scanner=new Scanner(System.in);
 25         String ex=scanner.next();
 26     
 27         List<String>getList=StringToList(ex);
 28         
 29         /*
 30         for(String data:getList){
 31             System.out.println(data);
 32         }
 33         */
 34         Stack<String> s1=new Stack<String>();
 35         Stack<String> s2=new Stack<String>();
 36         //List<String>s2=new ArrayList<String>();
 37         
 38         /*
 39          * 遍历存储中缀表达式的链表
 40          */
 41         for(String data:getList){
 42             if(data.matches("\\d+")){ //如果是数字,则压入s2栈
 43                 s2.push(data);
 44                 //s2.add(data);
 45                 
 46              //如果是括号
 47             }else if(data=="("){
 48                 s1.push(data);//左括号入s1栈
 49             }else if(data==")"){//右括号则在s1栈中找左括号,将括号中的全部元素从s1栈中弹出,并一次压入s2栈,执行完后,s1栈中将不含括号
 50                 while(s1.peek()!="("){
 51                     s2.push(s1.pop());
 52                     //s2.add(s1.pop());
 53                 }
 54                 s1.pop();//弹掉s1顶部的“(”
 55             }else{
 56                 //既不是数字,也不是括号,则为符号
 57                     while(s1.size()>=0){
 58                         if(s1.isEmpty()||s1.peek()=="("){
 59                             s1.push(data);
 60                             break;
 61                         }else if(getPriority(data)>getPriority(s1.peek())){
 62                             s1.push(data);
 63                             break;
 64                         }else{
 65                             s2.push(s1.pop());
 66                             //s2.add(s1.pop());
 67                         }
 68                     }
 69                 }
 70                 
 71             }
 72         
 73         //将s1中剩余的元素全部一次压入s2中
 74         while(s1.size()>0){
 75             s2.push(s1.pop());
 76         }
 77         
 78         
 79         /*
 80          * s2的逆序为原中缀表达式的逆序形式,新建一个链表存储后缀表达式
 81          */
 82         //1.首先新建一个栈,完成对s2的逆序
 83         Stack<String> temp=new Stack<String>();
 84         while(s2.size()>0){
 85             temp.push(s2.pop());
 86         }
 87         
 88         //2.用一个链表,将temp中的元素弹出并保存
 89         List<String>houZhui=new ArrayList<String>();
 90         
 91         while(temp.size()>0){
 92             houZhui.add(temp.pop());
 93         }
 94         
 95         
 96         
 97         for(String ele:houZhui){
 98             System.out.print(ele+",");
 99         }
100         System.out.println();
101         
102         /*
103         Stack<String> stack=new Stack<String>();//新建一个栈来进行运算
104         
105         
106                //此时houZhui链表中保存的为原中缀表达式的后缀表现形式,只需按照后缀表达式计算的方法来计算即可
107                 
108         for(String item:houZhui){
109                     //使用正则表达式匹配多位数
110                     if(item.matches("\\d+")){
111                         stack.push(item);//如果取出的是数,则入栈
112                     }else{//如果取出的是运算符,则弹出两个数进行运算,并将运算结果入栈
113                         int num2=Integer.parseInt(stack.pop());
114                         int num1=Integer.parseInt(stack.pop());
115                         int res=0;
116                         if(item.equals("+")){
117                             res=num1+num2;
118                         }else if(item.equals("-")){
119                             res=num1-num2;
120                         }else if(item.equals("*")){
121                             res=num1*num2;
122                         }else if(item.equals("/")){
123                             res=num1/num2;
124                         }else{
125                             throw new RuntimeException("运算符有误!!!");
126                         }
127                         stack.push(res+"");
128                     }
129                 }
130         
131                 
132                 int result=Integer.parseInt(stack.pop());
133         System.out.println(ex+"="+result);
134         
135         */
136         
137         
138         }
139         
140         }
141         
142         
143     
144     
145     
146     
147     //使用链表存储分割好后的中缀表达式 
148     public static List<String>StringToList(String ex){
149         List<String>ls=new ArrayList<String>();
150         int i=0;
151         String st;
152         while(i<ex.length()){
153             if(ex.charAt(i)<48||ex.charAt(i)>57){//如果是符号,则直接添加
154                 ls.add(ex.charAt(i)+"");
155                 i++;
156             }else{
157                 st="";
158                 //如果是数字,则需要考虑是否为多位数
159                 while((i<ex.length())&&(ex.charAt(i)>47&&ex.charAt(i)<58)){
160                     st=st+ex.charAt(i);
161                     i++;
162                 }
163                 ls.add(st);
164             }
165         }
166         return ls;
167     }
168     
169     public static int getPriority(String oper){
170         if(oper=="*"||oper=="/"){
171             return 1;
172         }else if(oper=="+"||oper=="-"){
173             return 0;
174         }else{
175             return -1;
176         }
177     }
178 
179 }

运行结果:

分析:有问题,括号没有除掉

原因:在进行括号判断时,使用了“==”进行判断,导致判断出错,本应该判断为是括号,结果判断的不是括号,导致括号那部分的程序没有执行

修改:将“==”改为.equals()判断方法

 

修改后的完整代码:

  1 package Zhan;
  2 
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 import java.util.Scanner;
  6 import java.util.Stack;
  7 
  8 /*
  9  * 将中缀表达式转换为后缀表达式,并计算结果
 10  * 步骤:
 11  * 1.遇到数字,将其压入s2;
 12  * 2.遇到括号:
 13  * (1)若为(,则压入s1栈;
 14  * (2)否则若为),则在s1中寻找(,将()中的元素全部从s1中弹出,并一次压入s2栈
 15  * 3.遇到运算符
 16  * (1)若s1栈为空或者s1栈顶是(,则入s1栈;
 17  * (2)否则,若此符号的优先级大于s1栈顶符号的优先级,则将此符号压入s1栈;
 18  * (3)否则,如此符号的优先级小于等于s1栈顶符号优先级,则将此时s1栈顶的符号弹出并压入s2栈,然后再回到第(1)步进行判断,并执行相应的程序,一直循环,直到s1为空为止
 19  */
 20 public class CalculateDemo {
 21     public static void main(String[] args){
 22         while(true){
 23         System.out.println("输入表达式:");
 24         Scanner scanner=new Scanner(System.in);
 25         String ex=scanner.next();
 26     
 27         List<String>getList=StringToList(ex);
 28         
 29         
 30         /*
 31         System.out.println("---------------------");
 32         for(String data:getList){
 33             System.out.print(data+" ");
 34         }
 35         System.out.println();
 36         System.out.println("---------------------");
 37         */
 38         
 39         
 40         Stack<String> s1=new Stack<String>();
 41         Stack<String> s2=new Stack<String>();
 42     
 43         
 44         /*
 45          * 遍历存储中缀表达式的链表
 46          */
 47         for(String data:getList){
 48             if(data.matches("\\d+")){ //如果是数字,则压入s2栈
 49                 s2.push(data);
 50                 
 51              //如果是括号
 52             }else if(data.equals("(")){
 53                 s1.push(data);//左括号入s1栈
 54             }else if(data.equals(")")){//右括号则在s1栈中找左括号,将括号中的全部元素从s1栈中弹出,并依次压入s2栈,执行完后,s1栈中将不含括号
 55                 while(true){
 56                     if((s1.peek()).equals("(")){
 57                         break;
 58                     }else{
 59                     s2.push(s1.pop());
 60                     }
 61                 }
 62                 s1.pop();//弹掉s1顶部的“(”
 63             }else{
 64                 
 65                 //既不是数字,也不是括号,则为符号
 66                     while(s1.size()>=0){
 67                         if(s1.isEmpty()||s1.peek().equals("(")){
 68                             s1.push(data);
 69                             break;
 70                         }else if(getPriority(data)>getPriority(s1.peek())){
 71                             s1.push(data);
 72                             break;
 73                         }else{
 74                             s2.push(s1.pop());
 75                         }
 76                     }
 77                 }
 78                 
 79             }
 80         
 81         //将s1中剩余的元素全部一次压入s2中
 82         while(s1.size()>0){
 83             s2.push(s1.pop());
 84         }
 85         
 86         
 87         /*
 88          * s2的逆序为原中缀表达式的逆序形式,新建一个链表存储后缀表达式
 89          */
 90         //1.首先新建一个栈,完成对s2的逆序
 91         Stack<String> temp=new Stack<String>();
 92         while(s2.size()>0){
 93             temp.push(s2.pop());
 94         }
 95         
 96         //2.用一个链表,将temp中的元素弹出并保存
 97         List<String>houZhui=new ArrayList<String>();
 98         
 99         while(temp.size()>0){
100             houZhui.add(temp.pop());
101         }
102         
103         
104         /*
105         for(String ele:houZhui){
106             System.out.print(ele+",");
107         }
108         System.out.println();
109         */
110         
111         
112         Stack<String> stack=new Stack<String>();//新建一个栈来进行运算
113         
114         
115                //此时houZhui链表中保存的为原中缀表达式的后缀表现形式,只需按照后缀表达式计算的方法来计算即可
116                 
117         for(String item:houZhui){
118                     //使用正则表达式匹配多位数
119                     if(item.matches("\\d+")){
120                         stack.push(item);//如果取出的是数,则入栈
121                     }else{//如果取出的是运算符,则弹出两个数进行运算,并将运算结果入栈
122                         int num2=Integer.parseInt(stack.pop());
123                         int num1=Integer.parseInt(stack.pop());
124                         int res=0;
125                         if(item.equals("+")){
126                             res=num1+num2;
127                         }else if(item.equals("-")){
128                             res=num1-num2;
129                         }else if(item.equals("*")){
130                             res=num1*num2;
131                         }else if(item.equals("/")){
132                             res=num1/num2;
133                         }else{
134                             throw new RuntimeException("运算符有误!!!");
135                         }
136                         stack.push(res+"");
137                     }
138                 }
139         
140                 
141                 int result=Integer.parseInt(stack.pop());
142         System.out.println(ex+"="+result);
143         
144         
145         
146         
147         }
148         
149         }
150         
151         
152     
153     
154     
155     
156     //使用链表存储分割好后的中缀表达式 
157     public static List<String>StringToList(String ex){
158         List<String>ls=new ArrayList<String>();
159         int i=0;
160         String st;
161         while(i<ex.length()){
162             if(ex.charAt(i)<48||ex.charAt(i)>57){//如果是符号,则直接添加
163                 ls.add(ex.charAt(i)+"");
164                 i++;
165             }else{
166                 st="";
167                 //如果是数字,则需要考虑是否为多位数
168                 while((i<ex.length())&&(ex.charAt(i)>47&&ex.charAt(i)<58)){
169                     st=st+ex.charAt(i);
170                     i++;
171                 }
172                 ls.add(st);
173             }
174         }
175         return ls;
176     }
177     
178     public static int getPriority(String oper){
179         if(oper=="*"||oper=="/"){
180             return 1;
181         }else if(oper=="+"||oper=="-"){
182             return 0;
183         }else{
184             return -1;
185         }
186     }
187 
188 }

运行结果:

posted @ 2021-02-26 01:04  L1998  阅读(61)  评论(0)    收藏  举报