蓝桥杯算法训练 java算法 表达式求值

问题描述
  输入一个只包含加减乖除和括号的合法表达式,求表达式的值。其中除表示整除。
输入格式
  输入一行,包含一个表达式。
输出格式
  输出这个表达式的值。
样例输入
1-2+3*(4-5)
样例输出
-4
 
问题分析:

1将运算式子转化为后缀表达式
2扫描后缀表达式,将数字依次进栈,当到运算符号时,出栈两个数字,进行运算,再将结果放进数字栈中
3最后数字栈最上面得到的即为结果,边扫描边进行运算
4关键点在后缀表达式的转化,下面是后缀表达式的要求
  4.1读到运算数字时,直接输出;
  4.2栈为空时,读到操作符,直接进栈;
  4.3左括号的优先级被视为比所有运算符低,读到左括号,直接进栈;
  4.4读到右括号,把栈中左括号上面的元素输出,并把左括号弹出;
  4.5读到其他运算符,输出所有优先级大于或等于该运算符的栈顶元素;
  4.6最后把栈中剩余的元素一一输出。

  4.7后缀表达式中没有()左右两个括号

例如该例子中5+12*(3+5)/7的后缀表达式为5 12 3 5 + * 7 / +
5有了后缀表达式进行计算
  5.1、 5 12 3 5 当扫描到+时3 5 出栈进行运算得到8 在进栈 栈中现在有5 12 8
  5.2、扫描到*时,12和8出栈,进行运算,得到96,进栈,栈中有5 96
  5.3、扫描到7,进栈,栈中有5 96 7
  5.4、扫描到/,96和7出栈,进行运算得到13.714....,进栈,栈中有5 13.714....
  5.5、扫描到+,5 13.714出栈,进行运算,得到18.714....这就是结果

下面是java代码,已经在蓝桥杯系统验证成功,此算法提示是整除,所以不用考虑小数问题

  1 import java.util.Collections;
  2 import java.util.Scanner;
  3 import java.util.Stack;
  4 public class Main {
  5     private Stack<String> houzhuiStack  = new Stack<String>();//后缀式栈
  6     private Stack<Character> yunsuanfuStack  = new Stack<Character>();//运算符栈
  7     private int [] operatPriority  = new int[] {0,3,2,1,-1,1,0,2};//运用运算符ASCII码-40做索引的运算符优先级
  8     public static void main(String[] args) {
  9         Scanner scanner = new Scanner(System.in);
 10         String s = scanner.nextLine();
 11         Main cal  = new Main();
 12         String result  = cal.calculate(s);
 13         System.out.println(result);
 14     }
 15     /*
 16      *2.得到后缀表达式进行运算
 17      */
 18     public String calculate(String expression) {
 19         Stack<String> resultStack  = new Stack<String>();
 20         prepare(expression);
 21         Collections.reverse(houzhuiStack);//将后缀式栈反转
 22         String firstValue  ,secondValue,currentValue;//参与计算的第一个值,第二个值和算术运算符
 23         while(!houzhuiStack.isEmpty()) {
 24             currentValue  = houzhuiStack.pop();
 25             if(!isOperator(currentValue.charAt(0))) {//如果不是运算符则存入操作数栈中
 26                 resultStack.push(currentValue);
 27             } else {//如果是运算符则从操作数栈中取两个值和该数值一起参与运算
 28                  secondValue  = resultStack.pop();
 29                  firstValue  = resultStack.pop();
 30                  String tempResult  = calculate(firstValue, secondValue, currentValue.charAt(0));
 31                  resultStack.push(tempResult);
 32             }
 33         }
 34         return resultStack.pop();
 35     }
 36     /**
 37      * 1数据准备阶段将表达式转换成为后缀式栈
 38      */
 39     private void prepare(String expression) {
 40         yunsuanfuStack.push(',');//运算符放入栈底元素逗号,此符号优先级最低
 41         char[] arr  = expression.toCharArray();
 42         int currentIndex  = 0;//当前字符的位置
 43         int count = 0;//上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
 44         char currentOp  ,peekOp;//当前操作符和栈顶操作符
 45         for(int i=0;i<arr.length;i++) {
 46             currentOp = arr[i];
 47             if(isOperator(currentOp)) {//如果当前字符是运算符
 48                 if(count > 0) {
 49                     houzhuiStack.push(new String(arr,currentIndex,count));//取两个运算符之间的数字
 50                 }
 51                 peekOp = yunsuanfuStack.peek();
 52                 if(currentOp == ')') {//遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
 53                     while(yunsuanfuStack.peek() != '(') {
 54                         houzhuiStack.push(String.valueOf(yunsuanfuStack.pop()));
 55                     }
 56                     yunsuanfuStack.pop();
 57                 } else {
 58                     while(currentOp != '(' && peekOp != ',' && compare(currentOp,peekOp) ) {
 59                         houzhuiStack.push(String.valueOf(yunsuanfuStack.pop()));
 60                         peekOp = yunsuanfuStack.peek();
 61                     }
 62                     yunsuanfuStack.push(currentOp);
 63                 }
 64                 count = 0;
 65                 currentIndex = i+1;
 66             } else {
 67                 count++;
 68             }
 69         }
 70         if(count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {//最后一个字符不是括号或者其他运算符的则加入后缀式栈中
 71             houzhuiStack.push(new String(arr,currentIndex,count));
 72         } 
 73         
 74         while(yunsuanfuStack.peek() != ',') {
 75             houzhuiStack.push(String.valueOf( yunsuanfuStack.pop()));//将操作符栈中的剩余的元素添加到后缀式栈中
 76         }
 77     }
 78     /**
 79      * 判断是否为算术符号
 80      */
 81     private boolean isOperator(char c) {
 82         return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' ||c == ')';
 83     }
 84     /**
 85      * 利用ASCII码-40做下标去算术符号优先级
 86      */
 87     public  boolean compare(char cur,char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
 88         boolean result  = false;
 89         if(operatPriority[(peek)-40] >= operatPriority[(cur) - 40]) {
 90            result = true;
 91         }
 92         return result;
 93     }
 94     /**
 95      * 按照给定的算术运算符做计算
 96      */
 97     private String calculate(String firstValue,String secondValue,char currentOp) {
 98         String result  = "";
 99         switch(currentOp) {
100             case '+':
101                 result = String.valueOf(ArithHelper.add(firstValue, secondValue));
102                 break;
103             case '-':
104                 result = String.valueOf(ArithHelper.sub(firstValue, secondValue));
105                 break;
106             case '*':
107                 result = String.valueOf(ArithHelper.mul(firstValue, secondValue));
108                 break;
109             case '/':
110                 result = String.valueOf(ArithHelper.div(firstValue, secondValue));
111                 break;
112         }
113         return result;
114     }
115 static class ArithHelper {
116     // 这个类不能实例化
117     private ArithHelper() {
118     }
119     /**
120      * 提供精确的加法运算。
121      * @param v1 被加数
122      * @param v2 加数
123      * @return 两个参数的和
124      */
125     public static String add(String v1, String v2) {
126         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
127         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
128         return String.valueOf(b1.add(b2).intValue());
129     }
130     /**
131      * 提供精确的减法运算。
132      * @param v1 被减数
133      * @param v2 减数
134      * @return 两个参数的差
135      */
136     public static String sub(String v1, String v2) {
137         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
138         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
139         return String.valueOf(b1.subtract(b2).intValue());
140     }
141     /**
142      * 提供精确的乘法运算。
143      * @param v1
144      *            被乘数
145      * @param v2
146      *            乘数
147      * @return 两个参数的积
148      */
149     public static String mul(String v1, String v2) {
150         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
151         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
152         return String.valueOf(b1.multiply(b2).intValue());
153     }
154     /**
155      * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
156      * @param v1
157      *            被除数
158      * @param v2
159      *            除数
160      * @return 两个参数的商
161      */
162     public static String div(String v1, String v2) {
163         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
164         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
165         return String.valueOf(b1.divideToIntegralValue(b2).intValue());
166     }
167 }
168 }

 下面的代码是考虑了不识字整除的情况。仅供参考

  1 import java.util.Collections;
  2 import java.util.Scanner;
  3 import java.util.Stack;
  4 public class 表达式求值 {
  5     private Stack<String> houzhuiStack  = new Stack<String>();//后缀式栈
  6     private Stack<Character> yunsuanfuStack  = new Stack<Character>();//运算符栈
  7     private int [] operatPriority  = new int[] {0,3,2,1,-1,1,0,2};//运用运算符ASCII码-40做索引的运算符优先级
  8     public static void main(String[] args) {
  9         Scanner scanner = new Scanner(System.in);
 10         String s = scanner.nextLine();
 11         表达式求值 cal  = new 表达式求值();
 12         double result  = cal.calculate(s);
 13         System.out.println(result);
 14     }
 15     /*
 16      *2.得到后缀表达式进行运算
 17      */
 18     public double calculate(String expression) {
 19         Stack<String> resultStack  = new Stack<String>();
 20         prepare(expression);
 21         Collections.reverse(houzhuiStack);//将后缀式栈反转
 22         String firstValue  ,secondValue,currentValue;//参与计算的第一个值,第二个值和算术运算符
 23         while(!houzhuiStack.isEmpty()) {
 24             currentValue  = houzhuiStack.pop();
 25             if(!isOperator(currentValue.charAt(0))) {//如果不是运算符则存入操作数栈中
 26                 resultStack.push(currentValue);
 27             } else {//如果是运算符则从操作数栈中取两个值和该数值一起参与运算
 28                  secondValue  = resultStack.pop();
 29                  firstValue  = resultStack.pop();
 30                  String tempResult  = calculate(firstValue, secondValue, currentValue.charAt(0));
 31                  resultStack.push(tempResult);
 32             }
 33         }
 34         return Double.valueOf(resultStack.pop());
 35     }
 36     
 37     /**
 38      * 1数据准备阶段将表达式转换成为后缀式栈
 39      */
 40     private void prepare(String expression) {
 41         yunsuanfuStack.push(',');//运算符放入栈底元素逗号,此符号优先级最低
 42         char[] arr  = expression.toCharArray();
 43         int currentIndex  = 0;//当前字符的位置
 44         int count = 0;//上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
 45         char currentOp  ,peekOp;//当前操作符和栈顶操作符
 46         for(int i=0;i<arr.length;i++) {
 47             currentOp = arr[i];
 48             if(isOperator(currentOp)) {//如果当前字符是运算符
 49                 if(count > 0) {
 50                     houzhuiStack.push(new String(arr,currentIndex,count));//取两个运算符之间的数字
 51                 }
 52                 peekOp = yunsuanfuStack.peek();
 53                 if(currentOp == ')') {//遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
 54                     while(yunsuanfuStack.peek() != '(') {
 55                         houzhuiStack.push(String.valueOf(yunsuanfuStack.pop()));
 56                     }
 57                     yunsuanfuStack.pop();
 58                 } else {
 59                     while(currentOp != '(' && peekOp != ',' && compare(currentOp,peekOp) ) {
 60                         houzhuiStack.push(String.valueOf(yunsuanfuStack.pop()));
 61                         peekOp = yunsuanfuStack.peek();
 62                     }
 63                     yunsuanfuStack.push(currentOp);
 64                 }
 65                 count = 0;
 66                 currentIndex = i+1;
 67             } else {
 68                 count++;
 69             }
 70         }
 71         if(count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {//最后一个字符不是括号或者其他运算符的则加入后缀式栈中
 72             houzhuiStack.push(new String(arr,currentIndex,count));
 73         } 
 74         
 75         while(yunsuanfuStack.peek() != ',') {
 76             houzhuiStack.push(String.valueOf( yunsuanfuStack.pop()));//将操作符栈中的剩余的元素添加到后缀式栈中
 77         }
 78     }
 79     
 80     /**
 81      * 判断是否为算术符号
 82      */
 83     private boolean isOperator(char c) {
 84         return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' ||c == ')';
 85     }
 86     
 87     /**
 88      * 利用ASCII码-40做下标去算术符号优先级
 89      */
 90     public  boolean compare(char cur,char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
 91         boolean result  = false;
 92         if(operatPriority[(peek)-40] >= operatPriority[(cur) - 40]) {
 93            result = true;
 94         }
 95         return result;
 96     }
 97     
 98     /**
 99      * 按照给定的算术运算符做计算
100      */
101     private String calculate(String firstValue,String secondValue,char currentOp) {
102         String result  = "";
103         switch(currentOp) {
104             case '+':
105                 result = String.valueOf(ArithHelper.add(firstValue, secondValue));
106                 break;
107             case '-':
108                 result = String.valueOf(ArithHelper.sub(firstValue, secondValue));
109                 break;
110             case '*':
111                 result = String.valueOf(ArithHelper.mul(firstValue, secondValue));
112                 break;
113             case '/':
114                 result = String.valueOf(ArithHelper.div(firstValue, secondValue));
115                 break;
116         }
117         return result;
118     }
119 
120 static class ArithHelper {
121     // 默认除法运算精度
122     private static final int DEF_DIV_SCALE = 16;
123     // 这个类不能实例化
124     private ArithHelper() {
125     }
126 
127     /**
128      * 提供精确的加法运算。
129      * @param v1 被加数
130      * @param v2 加数
131      * @return 两个参数的和
132      */
133 
134     public static double add(double v1, double v2) {
135         java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
136         java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
137         return b1.add(b2).doubleValue();
138     }
139     
140     public static double add(String v1, String v2) {
141         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
142         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
143         return b1.add(b2).doubleValue();
144     }
145 
146     /**
147      * 提供精确的减法运算。
148      * @param v1 被减数
149      * @param v2 减数
150      * @return 两个参数的差
151      */
152 
153     public static double sub(double v1, double v2) {
154         java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
155         java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
156         return b1.subtract(b2).doubleValue();
157     }
158     
159     public static double sub(String v1, String v2) {
160         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
161         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
162         return b1.subtract(b2).doubleValue();
163     }
164 
165     /**
166      * 提供精确的乘法运算。
167      * @param v1
168      *            被乘数
169      * @param v2
170      *            乘数
171      * @return 两个参数的积
172      */
173 
174     public static double mul(double v1, double v2) {
175         java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
176         java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
177         return b1.multiply(b2).doubleValue();
178     }
179     
180     public static double mul(String v1, String v2) {
181         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
182         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
183         return b1.multiply(b2).doubleValue();
184     }
185 
186     /**
187      * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
188      * @param v1
189      *            被除数
190      * @param v2
191      *            除数
192      * @return 两个参数的商
193      */
194 
195     public static double div(double v1, double v2) {
196         return div(v1, v2, DEF_DIV_SCALE);
197     }
198     
199     public static double div(String v1, String v2) {
200         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
201         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
202         return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
203     }
204 
205     /**
206      * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
207      * @param v1 被除数
208      * @param v2 除数
209      * @param scale 表示表示需要精确到小数点以后几位。
210      * @return 两个参数的商
211      */
212 
213     public static double div(double v1, double v2, int scale) {
214         if (scale < 0) {
215             throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
216         }
217         java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
218         java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
219         return b1.divide(b2, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
220     }
221 
222     /**
223      * 提供精确的小数位四舍五入处理。
224      * @param v 需要四舍五入的数字
225      * @param scale 小数点后保留几位
226      * @return 四舍五入后的结果
227      */
228 
229     public static double round(double v, int scale) {
230         if (scale < 0) {
231             throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
232         }
233         java.math.BigDecimal b = new java.math.BigDecimal(Double.toString(v));
234         java.math.BigDecimal one = new java.math.BigDecimal("1");
235         return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
236     }
237     
238     public static double round(String v, int scale) {
239         if (scale < 0) {
240             throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
241         }
242         java.math.BigDecimal b = new java.math.BigDecimal(v);
243         java.math.BigDecimal one = new java.math.BigDecimal("1");
244         return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
245     }
246 }
247 }
View Code
原文地址:https://www.cnblogs.com/zhangxue521/p/6575009.html