蓝桥杯——表达式计算(支持多位数运算的java实现)

来源:互联网 发布:奇虎软件怎么样 编辑:程序博客网 时间:2024/05/18 00:54

注:该题解题思路是bz参考博客:http://blog.csdn.net/reidsc/article/details/54669433是使用c++实现

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

  表达式长度不超过100,表达式运算合法且运算过程都在int内进行。


其实要做出这道题,首先要知道如何将中缀表达式转换成后缀表达式,还有就是如何计算后缀表达式的结果;

能够正确的计算出例如:样例输入1-2+3*(4-5)的后缀表达式并且算出其结果那么这倒题其实已经快要做出来了

中缀表达式1-2+3*(4-5)的后缀表达式就是12-345-*+;其结果是-4;


下面就是在java如何将中缀表达式转换成后缀表达式,以及如何计算后缀表达式的原则和方法:

此处参考博客:http://blog.csdn.net/reidsc/article/details/54669433

1.将中缀表达式转换为后缀表达式的方法:
(1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2;
(2) 从左至右扫描中缀表达式;
(3) 遇到操作数时,将其压入S2,这里由于运算数可能大于10,所以如果数字后面一个符号是运算符,则将‘#’入S2栈充当分割线;
(4) 遇到运算符时有三种情况:
(4-1) 三种情况下直接入S1栈①S1为空②运算符为‘(’③运算符优先级比S1栈顶运算符的高
(4-2)如果右括号“)”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃
(4-3) 若运算符优先级小于或等于S1栈顶运算符的优先级,则依次弹出S1栈顶元素,直到运算符的优先级大于S1栈顶运算符优先级
(6) 重复步骤(2)至(5),直到表达式的最右边;
(7) 将S1中剩余的运算符依次弹出并压入S2;
(8) 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式。

运算符优先级: 左括号>(乘=除)>(加=减)>右括号  为了编程方便假定右括号优先级最小。

tip:“(”当成一个特殊的运算符来处理,即遇到“(”直接入栈,如果栈顶元素是“(”,那么由于我们将“(”的优先级设成了最高的,

那么如果不做出相应的特殊处理那么“(”将会被弹出,这不是我们想看到的,所以我们设定如果栈顶元素是“(”那么下一个运算符无论

其优先级的高低,都直接入栈。


2.后缀表达式计算方法:

(1)定义一个int栈S3,定义一个整形数组num用来存储大于10的数字便于计算,从左至右扫描表达式。

(2)遇到数字时:

(2-1)若数字后面一个元素不是#(数字后面只可能是#或数字)则将数字字符转化为数字存在num[ ]数组中;

(2-2)若数字后面一个元素是#,将num数组中保存的数字算出来并压入S3栈中。

(3)遇到运算符时,弹出S3栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。


import java.util.Scanner;import java.util.Stack;public class CountExperssion {private static Stack<Integer> stackN = new Stack<Integer>();// 数字private static Stack<Character> stackF = new Stack<Character>();// 符号private static Stack<Character> stackZ = new Stack<Character>();// 中间private static char [] ch;private static char [] ch1;// 中间字符数组private static int [] num = new int[10];public static void main(String[] args) {Scanner in = new Scanner(System.in);String str = in.next();ch = str.toCharArray();int result = countHou(zhongToHou(ch));System.out.println(result);in.close();}public static int compareYXJ(char c){// 用来输出运算符的优先级if(c == ')'){return 1;}else if(c == '+' || c == '-'){return 2;}else if(c == '*' || c == '/'){return 3;}else if(c == '('){return 4;}return 999;}public static int operation(int a, int b, char c){// 计算方法if(c == '+'){return a + b;}else if(c == '-'){return b - a;}else if(c == '*'){return a * b;}else if(c == '/' && a != 0){return b / a;}return -1;}public static char[] zhongToHou(char [] ch){// 中缀表达式转换成后缀表达式int n = ch.length;String str = "";for(int i = 0; i < n; i++){if(ch[i] >= '0' && ch[i] <= '9'){// 判断是否是数字if(i + 1 < n && (ch[i+1] < '0' || ch[i+1] > '9') || i + 1 == n){// 如果一个数字的后面是运算符stackZ.push(ch[i]);stackZ.push('#');}else{// 如果是数字的情况stackZ.push(ch[i]);}}else{// 是运算符if(stackF.isEmpty() || ch[i]=='(' || compareYXJ(ch[i]) > compareYXJ(stackF.peek())){// 如果运算符栈为空或者该运算符比栈顶运算符的优先级高的时候直接入栈stackF.push(ch[i]);}else if(ch[i] == ')'){// 当是右括号的时候while(stackF.peek() != '('){stackZ.push(stackF.pop());}stackF.pop();}else{// 优先级低于栈顶运算符的时候while(!stackF.isEmpty() && compareYXJ(ch[i]) <= compareYXJ(stackF.peek()) && stackF.peek() != '('){stackZ.push(stackF.pop());}stackF.push(ch[i]);}}}while(!stackF.isEmpty()){// 当表达式走完之后将符号栈中的符号全部弹出压入中间数字栈stackZ.push(stackF.pop());}while(!stackZ.isEmpty()){// 将中间栈中的值全部弹出得到一个倒转的后缀表达式str += stackZ.pop()+"";}ch1 = str.toCharArray();int a = ch1.length;for(int i = 0; i < a/2; i++){// 该算法将ch1反转char t;t = ch1[i];ch1[i] = ch1[a-1-i];ch1[a-1-i] = t;}return ch1;}public static int countHou(char [] ch){// 计算后缀表达式int n = ch.length;int sum = 0;int k = 0;int tmp = 0;for(int i = 0; i < n; i++){if(ch[i] == '#'){continue;}else if(ch[i] == '+' || ch[i] == '-' || ch[i] == '*' || ch[i] == '/'){// 如果是运算符,则弹出连个数字进行运算sum = operation(stackN.pop(), stackN.pop(), ch[i]);stackN.push(sum);}else{// 如果是数字if(ch[i+1] == '#'){// 如果下一个是‘#’num[k++] = ch[i] - '0';for(int j = 0; j < k; j++){tmp += (num[j] * (int)Math.pow(10, k-j-1));}stackN.push(tmp);tmp = 0;k = 0;}else{// 下一个元素是数字num[k++] = ch[i] - '0';}}}return stackN.peek();}}


1 0