栈
中缀表达式就是形如a(b-c)+d*这样我们平常写的式子,如果按平时逻辑上的处理顺序的话计算机比较难正确处理,因为运算符之间有优先级,括号的优先级比乘除高,乘除的优先级比加减高,这是小学的知识。
如果利用栈的先进后出(First In Last Out)的特性,可以将中缀表达式转为后缀表达式。
后缀表达式不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:(2 + 1) * 3 , 即2 1 + 3 *
思路
- 读入字符
- 如果读入的字符为操作符,则压栈,如果是操作数,则输出
- 如果读入的 操作符优先级比栈顶元素低,则弹出栈操作符直至遇到比读入的操作符优先级更低的操作符。左括号( 为特殊情况,读入时当作高优先级,弹出时为低优先级,直至读入一个) 右括号,然后弹出栈中第一个左括号及其之前的所有操作符
根据后缀表达式计算结果
当见到一个数时就把它推入栈中,在遇到一个操作符时该操作符就作用于从该栈弹出的两个操作数上,再将所得的结果推出栈中。
public class Postfix {
//用于记录操作符
private static LinkedList<String> operators=new LinkedList<>();
//用于记录输出
private static LinkedList<String> output=new LinkedList<>();
//用于展示后缀表达式
private static StringBuilder sb=new StringBuilder();
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<>();
Scanner scanner=new Scanner(System.in);
String s;
//#号结束输入,输入的字符间要有空格,方便处理
while (!(s=scanner.next()).equals("#")) {
list.add(s);
}
transferToPostfix(list);
scanner.close();
}
//中缀表达式转为后缀表达式
private static void transferToPostfix(LinkedList<String> list){
Iterator<String> it=list.iterator();
while (it.hasNext()) {
String s = it.next();
if (isOperator(s)) {
if (operators.isEmpty()) {
operators.push(s);
}
else {
//如果读入的操作符为非")"且优先级比栈顶元素的优先级高或一样,则将操作符压入栈
if (priority(operators.peek())<=priority(s)&&!s.equals(")")) {
operators.push(s);
}
else if(!s.equals(")")&&priority(operators.peek())>priority(s)){
while (operators.size()!=0&&priority(operators.peek())>=priority(s)
&&!operators.peek().equals("(")) {
if (!operators.peek().equals("(")) {
String operator=operators.pop();
sb.append(operator).append(" ");
output.push(operator);
}
}
operators.push(s);
}
//如果读入的操作符是")",则弹出从栈顶开始第一个"("及其之前的所有操作符
else if (s.equals(")")) {
while (!operators.peek().equals("(")) {
String operator=operators.pop();
sb.append(operator).append(" ");
output.push(operator);
}
//弹出"("
operators.pop();
}
}
}
//读入的为非操作符
else {
sb.append(s).append(" ");
output.push(s);
}
}
if (!operators.isEmpty()) {
Iterator<String> iterator=operators.iterator();
while (iterator.hasNext()) {
String operator=iterator.next();
sb.append(operator).append(" ");
output.push(operator);
iterator.remove();
}
}
System.out.println("后缀: "+sb);
calculate();
//Collections.reverse(output);
}
//根据后缀表达式计算结果
private static void calculate(){
LinkedList<String> mList=new LinkedList<>();
String[] postStr=sb.toString().split(" ");
for (String s:postStr) {
if (isOperator(s)){
if (!mList.isEmpty()){
int num1=Integer.valueOf(mList.pop());
int num2=Integer.valueOf(mList.pop());
if (s.equals("/")&&num1==0){
System.out.println("除数不能为0");
return;
}
int newNum=cal(num2,num1,s);
mList.push(String.valueOf(newNum));
}
}
else {
//数字则压入栈中
mList.push(s);
}
}
if (!mList.isEmpty()){
System.out.println("result: "+mList.pop());
}
}
//判断是否操作符
private static boolean isOperator(String oper){
if (oper.equals("+")||oper.equals("-")||oper.equals("/")||oper.equals("*")
||oper.equals("(")||oper.equals(")")) {
return true;
}
return false;
}
//计算操作符的优先级
private static int priority(String s){
switch (s) {
case "+":return 1;
case "-":return 1;
case "*":return 2;
case "/":return 2;
case "(":return 3;
case ")":return 3;
default :return 0;
}
}
private static int cal(int num1,int num2,String operator){
switch (operator){
case "+":return num1+num2;
case "-":return num1-num2;
case "*":return num1*num2;
case "/":return num1/num2;
default :return 0;
}
}
}
结果
6 * ( 5 + ( 2 + 3 ) * 8 + 3 )
#
后缀: 6 5 2 3 + 8 * + 3 + *
result: 288