1、问题描述
当一个算术表达式中含有多个运算符,且运算符的优先级不同的情况下,如何才能处理一个算术表达式?????
2、思路
首先我们要知道表达式分为三类:
①中缀表达式:a+(b-c/d)*e
②前缀表达式+a*-b/cde
③后缀表达式abcd/-e*+
由于运算符有优先级,所以在计算机中计算一个中缀的表达式非常困难,特别是带括号的更麻烦,而后缀表达式中既无运算符优先又无括号的约束问题因为在后缀表达式中运算符出现的顺序正是计算的顺序,所以计算一个后缀的表达式更简单。
所以,可以将求算术表达式的值的过程化成两个过程:
1.将一个中缀表达式化成一个后缀表达式
2.对后缀表达式进行求值
一、将中缀变成一个后缀
因为要将运算符出现的次序与真正的算术运算顺序一直, 所以,就要让优先级高的以及括号内的运算符出现在前面,
因此要使用一个栈来保留还未送往后缀表达式的运算符,此栈称为运算符栈
算法描述如下:
(1)初始化一个运算符栈
(2)从算术表达式输入的字符串中,从左到右的读取一个字符
(3)若当前的 字符是操作数,则直接送往后缀表达式
(4)若当前的字符是左括号,则将其压入运算符栈
(5)若当前的字符是操作符,则进行如下 操作:
①当运算符栈为空时,直接将其压入栈。
②当此运算符的优先级高于栈顶的运算符时,则将此运算符压入栈,否则,弹出栈顶运算符送往后缀式,并将当前运算符压栈,重复步骤(5)
(6)若当前字符是右括号,反复将栈顶符号弹出,并送往后缀表达式中,知道栈顶元素为左括号为止,然后将左括号出栈并丢弃
(7)若读取还未结束,则重复步骤(2)
(8)若读取结束,则将栈中剩余的所有的运算符弹出并送往后缀表达式
二、计算后缀表达式的值
计算步骤很简单,就是找到运算符,然后找前面最后出现的两个操作数,从而构成一个最小的算术表达式进行运算,
在计算过程中也需要利用一个栈来保留后缀表达式中还未参与运算的操作数,称为操作数栈,
算法描述如下:
(1)初始化一个操作数栈
(2)从左到右依次读入后缀表达式中的字符
①若当前字符是操作数,则压入操作数栈。
②若当前字符是操作符,则从栈顶弹出两个操作数参与运算,并将运算结果压入操作数栈内。
(3)重复步骤(2)直到读入的后缀表达式结束为止,则操作数栈中的栈顶元素即为后缀表达式的结果
3、代码实现
public class ArithExpEvaluation {
public static void main(String[] args) {
ArithExpEvaluation p = new ArithExpEvaluation();
Scanner scan = new Scanner(System.in);
System.out.println("请输入算术表达式: ");
while (scan.hasNext()) {
String str = scan.next();
String postFix = p.conver2Postfic(str);
System.out.println("结果是: " + p.numberCalculate(postFix));
System.out.println();
System.out.println("请输入算术表达式: ");
}
}
public String conver2Postfic(String expression) {
Stack stack = new Stack();
stack.push('#');
String postFix = "";
for (int i = 0; i < expression.length()&&expression!=null; i++) {
char c = expression.charAt(i);
if (' ' != c) {
if (isOpenParenthesis(c)) {
stack.push(c);
} else if (isCloseParenthesis(c)) {
Character ac = (Character) stack.pop();
while (!isOpenParenthesis(ac)) {
postFix += ac.toString();
ac = (Character) stack.pop();
}
} else if (isOperator(c)) {
if (!stack.isEmpty()) {
Character ac = (Character) stack.pop();
while (ac != null &&ac!='#' && priority(ac.charValue()) >=priority(c)) {
postFix += ac;
ac = (Character) stack.pop();
}
if (ac != null) {
stack.push(ac);
}
}
stack.push(c);
} else {
postFix += c;
}
}
}
while (!stack.isEmpty() && stack.peek()!=(Character)'#') {
postFix += stack.pop().toString();
}
System.out.println(postFix);
return postFix;
}
public double numberCalculate(String postfix) {
Stack stack = new Stack();
for (int i = 0; i < postfix.length(); i++) {
char c = postfix.charAt(i);
if (isOperator(c)) {
double d1 = Double.parseDouble(stack.pop().toString());
double d2 = Double.parseDouble(stack.pop().toString());
double d3 = 0;
switch (c) {
case '+':
d3 = d2 + d1;
break;
case '-':
d3 = d2 - d1;
break;
case '*':
d3 = d2 * d1;
break;
case '/':
d3 = d2 / d1;
break;
case '%':
d3 = d2 % d1;
break;
case '^':
d3 = Math.pow(d2, d1);
break;
default:
break;
}
stack.push(d3);
} else {
stack.push(c);
}
}
return (double) stack.pop();
}
/**
* 求运算符的优先级
*
* @param c
* @return
*/
private int priority(char c) {
switch (c) {
case '^':
return 3;
case '*':
case '/':
case '%':
return 2;
case '+':
case '-':
return 1;
}
return 0;
}
/**
* 是否是一个操作符
*
* @param c
* @return
*/
private boolean isOperator(char c) {
if ('+' == c || '-' == c || '*' == c || '%' == c|| '/' == c || '^' == c ) {
return true;
}
return false;
}
/**
* 是否是一个右括号
*
* @param c
* @return
*/
private boolean isCloseParenthesis(char c) {
return ')' == c;
}
/**
* 是否是一个左括号
*
* @param c
* @return
*/
private boolean isOpenParenthesis(char c) {
return '(' == c;
}
}
不过有一点就是只能进行个位数的运算。
转载自:
http://blog.csdn.net/u011446177/article/details/42389511
另外有个博文不错,可以参考:中缀表达式转换为后缀表达式
http://blog.csdn.net/sgbfblog/article/details/8001651