基于逆波兰表达式的数学表达式计算器(Java版)
问题描述
输入一个数学表达式,有不同优先级的运算符和括号,计算表达式的结果
理论分析与算法
定义:
二元运算符位于两个操作数之间的表达式成为中缀表达式。一般输入的数学表达式都是中缀表达式。与之相对应的,二元操作符位于两个操作数之后的表达式称为后缀表达式(又称逆波兰表达式),二元运算符位于两个操作数之前的表达式称为前缀表达式。中缀表达式(逆波兰表达式)便于计算机计算。
算法:
----------------------------------------
1. 将输入的中缀表达式转化为后缀表达式【Algorithm 1】
2. 计算后缀表达式【Algorithm 2】
----------------------------------------
【Algorithm 1】中缀表达式 -> 后缀表达式
初始化操作数栈operand
初始化运算符栈operator
1. 从左到右扫描输入的中缀表达式
2. 如果此字符是操作数,则operand入栈
3. 如果此字符是运算符
3.1 如果该运算符是"(",operator入栈
3.2 如果该运算符是"+,-,*,/",从栈顶开始,与该运算符相比优先级相等或更高的运算符依次operator出栈并operand入栈,直到栈顶是比该运算符优先级低的运算符或"("或operator栈空,然后该运算符自己operator入栈
3.3 如果该运算符是")",从栈顶开始运算符依次operator出栈并operand入栈直到栈顶是"("
4. 此时操作数栈operand从栈底到栈顶就是后缀表达式
【Algorithm 2】计算后缀表达式的值
初始化计算栈answer
1. 从左到右扫描后缀表达式
2. 如果此字符是数字,则answer入栈
3. 如果此字符是运算符,则取answer栈顶2个元素计算,将计算结果answer入栈
4. 最后answer中剩下的那个数就是后缀表达式的计算结果
代码
简单起见,仅考虑一位整数和加法、乘法两种运算符以及括号
核心算法类
/*
* 表达式计算器类
* 支持一位整数的加法、乘法、括号的综合表达式计算
算法:
----------------------------------------
1. 将输入的中缀表达式转化为后缀表达式【Algorithm 1】
2. 计算后缀表达式【Algorithm 2】
----------------------------------------
【Algorithm 1】中缀表达式 -> 后缀表达式
初始化操作数栈operand
初始化运算符栈operator
1. 从左到右扫描输入的中缀表达式
2. 如果此字符是操作数,则operand入栈
3. 如果此字符是运算符
3.1 如果该运算符是"(",operator入栈
3.2 如果该运算符是"+,-,*,/",从栈顶开始,与该运算符相比优先级相等或更高的运算符依次operator出栈并operand入栈,直到栈顶是比该运算符优先级低的运算符或"("或operator栈空,然后该运算符自己operator入栈
3.3 如果该运算符是")",从栈顶开始运算符依次operator出栈并operand入栈直到栈顶是"("
4. 此时操作数栈operand从栈底到栈顶就是后缀表达式
【Algorithm 2】计算后缀表达式的值
初始化计算栈answer
1. 从左到右扫描后缀表达式
2. 如果此字符是数字,则answer入栈
3. 如果此字符是运算符,则取answer栈顶2个元素计算,将计算结果answer入栈
4. 最后answer中剩下的那个数就是后缀表达式的计算结果
*/
package expression;
import calculator.Calculator;
import java.util.Stack;
public class ExpressionCal extends Calculator{
public int calculateExpr(String expr)
{
// 1. 将中缀表达式化成后缀表达式
Stack<Character> operand = new Stack<Character>(); // 操作数栈
Stack<Character> operator = new Stack<Character>(); // 运算符栈
int i = 0, len = expr.length();
char c,c1; // c:接收expr的字符, c1:operator栈顶弹出的元素
for (i=0; i<len; i++)
{
c = expr.charAt(i); // 当前字符
if (Character.isDigit(c)) // 如果是操作数,则入operand栈
{
operand.add(c);
}
else // 如果是运算符
{
if (operator.empty()) // 如果operator栈空,入operator栈
{
operator.add(c);
}
else
{
if (c=='+') // c是低优先级元素
{
c1 = operator.pop(); // 取出operator栈顶元素
while (c1!='(') // 只要c1不是(
{
operand.add(c1); // 将c1加入operand
if (!operator.empty()) // 如果operator不空
{
c1 = operator.pop(); // 取出operator栈顶元素
}
else
{
break; // 如果operator空则结束循环
}
}
if (c1=='(') // 如果c1是(
{
operator.add(c1); // 还把c1放回去
}
operator.add(c); // 最后把c加入operator
}
else if (c=='*') // 如果c是高优先级元素
{
c1 = operator.pop(); // 从operator栈顶弹出一个元素
while (c1=='*') // 只要是*
{
operand.add(c1); // 将这个*入栈operand
if (!operator.empty()) // 如果operator非空
{
c1 = operator.pop(); // 从operator栈顶弹出一个元素
}
else
{
break; // 空则退出
}
}
if (c1!='*')
{
operator.add(c1); // 弹出来不是*的运算符要记得放回去
}
operator.add(c); // c入栈operator
}
else if (c=='(') // 如果c是(
{
operator.add(c); // 直接入栈
}
else if (c==')') // 如果c是)
{
c1 = operator.pop(); // 取出operator栈顶元素
while (c1!='(') // 只要c1不是(
{
operand.add(c1); // 将c1加入operand
if (!operator.empty()) // 如果operator不空
{
c1 = operator.pop(); // 取出operator栈顶元素
}
else
{
break; // 如果operator空则结束循环
}
}
}
}
}
}
while (!operator.empty()) // 表达式扫描结束后
{
c1 = operator.pop(); // 从栈顶依次取出operator中剩余的运算符
operand.add(c1); // 入栈operand
}// 至此,后缀表达式存储在operand栈中
// 2. 求解后缀表达式
Stack<Integer> ans = new Stack<Integer>(); // 计算结果
int cint, cint1; // 由字符opr转化而成的整数
for (Character opr : operand) // 从左到右扫描operand
{
if (Character.isDigit(opr)) // 如果opr是数字
{
cint = (int)(opr-'0'); // 将opr转化为int
ans.add(cint); // 将cint入栈ans
}
else if (opr=='+') // 是加号
{
cint = ans.pop(); // 从ans栈顶弹出两个数cint和cint1
cint1 = ans.pop();
cint = addition(cint,cint1); // 两数相加
ans.add(cint); // 计算结果写回ans
}
else if (opr=='*') // 是乘号
{
cint = ans.pop(); // 从ans栈顶弹出两个数cint和cint1
cint1 = ans.pop();
cint = multiple(cint,cint1); // 两数相加
ans.add(cint); // 计算结果写回ans
}
}
return ans.pop(); // 最后ans栈中剩下的那个数就是计算结果
}
}
测试运行类
/*
* 运行表达式计算类ExpressionCal的main方法入口
* 从控制台输入表达式,在控制台输出计算结果
*/
package expression;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class RunExpressionCal {
public static void main(String args[])
{
try
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println
("Please enter an expression with +,*,() and 1-digit integer:");
String expr = br.readLine();
ExpressionCal exprcal = new ExpressionCal();
int ans = exprcal.calculateExpr(expr);
System.out.println("The answer is: "+ans);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}