注:该题解题思路是bz参考博客:http://blog.csdn.net/reidsc/article/details/54669433是使用c++实现的
表达式长度不超过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();
}
}