package com.stack;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
//逆波兰计算器
/*
* 计算器主要方法:1计算器中缀转后缀
* 思路:
* 遍历中缀表达式集合
* 如果是数字直接放到集合
* 如果是运算符:
* 1判断栈是否为空或者栈顶为左括号,直接入栈
* 2如果栈不为空,且该运算符优先级高于栈顶优先级,直接入栈
* 3如果该运算符优先级小于等于栈顶优先级,将栈顶元素抛出放至集合中,循环此操作,直至高于栈顶元素优先级或栈为空,将此运算符放入栈中
* 如果是左括号,直接入栈
* 如果是右括号,将栈中元素抛出放至集合,直至栈顶元素为左括号,左括号抛出不入栈
* 遍历结束:栈中剩余元素依次弹出放至集合
* 2 计算后缀表达式
* 遍历后缀表达式
* 遇到数字直接入栈
* 遇到运算符抛出两个栈顶元素运算后结果入栈
* 循环此操作,直至集合为空,栈中剩余一个元素为结果
* */
public class Calculator {
//获取运算符优先级
public int getPriority(String param){
if("+".equals(param)||"-".equals(param)){
return 0;
}
if("/".equals(param)||"*".equals(param)){
return 1;
}
return -1;
}
//判断是否位数字
public boolean isNumber(String param){
return param.matches("\\d+");
}
//判断是否为操作符
public boolean isOperator(String param){
return "+".equals(param)||"-".equals(param)||"*".equals(param)||"/".equals(param);
}
//字符串转中缀表达式(此方法只支持一位整数,如果想要多位小数或整数可以在此方法添加判定方式)
public List toList(String param){
List<String> list=new ArrayList<>();
int index=0;
while(index<=param.length()-1){
list.add(param.substring(index,index+1));
index++;
}
return list;
}
//中缀表达式转后缀表达式
public List toSuffixList(List<String> list){
//栈用来临时存储字符
Stack<String> stack=new Stack<>();
//集合用于存放中缀表达式
List<String> suffixList=new ArrayList<>();
for(String item: list){
//如果是数字
if(isNumber(item)){
suffixList.add(item);
}
//如果是运算符
if(isOperator(item)){
//如果栈为空或者字符是左括号
if(stack.isEmpty()||"(".equals(stack.peek())){ stack.push(item);}
//如果栈不为空
else{
while (!stack.isEmpty()){
//如果此字符优先级比栈顶高,直接入栈
if(getPriority(item)>getPriority(stack.peek())){break;}
//如果字符优先级没有比栈顶高
if(getPriority(item)<=getPriority(stack.peek())){
//弹出栈顶元素放入集合
suffixList.add(stack.pop());
}
}
//运算符入栈
stack.push(item);
}
}
//如果是左括号
if("(".equals(item)){
stack.push(item);
}
//如果是右括号
if(")".equals(item)){
//弹出栈中数据,直至碰到左括号
while (!stack.peek().equals("(")){
suffixList.add(stack.pop());
}
//弹出左括号
stack.pop();
}
}
//遍历完毕中缀表达式,将栈中数据依次弹出放至集合
while(!stack.isEmpty()){
suffixList.add(stack.pop());
}
return suffixList;
}
//使用后缀表达式计算运算结果
public String Calculate(List<String> suffixList){
//栈用来临时存放数据
Stack<String> stack=new Stack<>();
for(String item: suffixList){
if(isNumber(item)){
stack.push(item);
}
//遇见运算符从栈中弹出两个数字进行运算后放入栈中
if(isOperator(item)){
if("+".equals(item)){
stack.push(""+(Double.valueOf(stack.pop())+Double.valueOf(stack.pop())));
}
if("-".equals(item)){
double top1= Double.parseDouble(stack.pop());
double top2= Double.parseDouble(stack.pop());
stack.push(""+(top2-top1));
}
if("*".equals(item)){
stack.push(""+(Double.valueOf(stack.pop())*Double.valueOf(stack.pop())));
}
if("/".equals(item)){
double top1= Double.parseDouble(stack.pop());
double top2= Double.parseDouble(stack.pop());
//格式化结果,保留两位小数
DecimalFormat decimalFormat=new DecimalFormat("#.00");
double result= Double.parseDouble(decimalFormat.format(top2/top1));
stack.push(""+result);
}
}
}
//栈中最后一个元素为结果
return stack.pop();
}
}
测试:
@Test
public void test(){
Calculator calculator=new Calculator();
String a="1+((2+3)*4)/6";
System.out.println(calculator.toList(a));
System.out.println(calculator.toSuffixList(calculator.toList(a)));
System.out.println(calculator.Calculate(calculator.toSuffixList(calculator.toList(a))));
}