逆波兰计算器
主要步骤:
- 将字符串转为List
- 中缀转后缀(重点!!!!)
- 实现逆波兰计算器
具体代码如下:
public static void main(String[] args) {
//将字符串转为List
String result = replaceSpace("-35-(33 + (4 + 5))");
List<String> originList = strToList(result);
System.out.println(originList);
//中缀转后缀
List<String> transList = transfer(originList);
System.out.println(transList);
//逆波兰计算器
int res = calculate(transList);
System.out.println(res);
}
/**
* 将输入的字符串转List,同时处理多位数情况
* -35-(33+(4+5)) ====》 [-, 35, -, (, 33, +, (, 4, +, 5, ), )]
* @param s 输入的字符串
* @return List
*/
public static List<String> strToList(String s){
List<String> resList = new ArrayList<>();
int i = 0;
while (i < s.length()) {
if (Character.isDigit(s.charAt(i))) {
long num = 0;
while (i < s.length() && Character.isDigit(s.charAt(i))) {
num = num * 10 + s.charAt(i) - '0';
i++;
}
resList.add(num + "");
} else {
resList.add(s.charAt(i) + "");
i++;
}
}
return resList;
}
/**
* 中缀转后缀
* 该处我做了改动,使用对0做加减来表示符号位,有点蠢但是好理解
* [-, 35, -, (, 33, +, (, 4, +, 5, ), )] ====》 [0, 35, -, 33, 4, 5, +, +, -]
* @param list
* @return
*/
private static List<String> transfer(List<String> list) {
//创建一个符号栈
Stack<String> stack = new Stack<>();
//创建一个用于存放结果的集合
List<String> resList = new ArrayList<>();
//遍历原始集合
for (int i=0; i<list.size(); i++) {
String cur = list.get(i); //cur为当前字符串
if ("(".equals(cur)){
//当为左括号时,直接入符号栈
stack.push(cur);
}else if (")".equals(cur)){
//当为右括号时,遍历符号栈,当找到对应左括号时退出循环
while (!"(".equals(stack.peek())){
//若不是对应的左括号,则将该位出栈,并加入到结果集合中
resList.add(stack.pop());
}
//若找到对应的左括号,则退出循环,并将该左括号出栈
stack.pop();
}else if (isNumber(cur)){
//当为数字时,直接加入结果集
resList.add(cur);
}else {
//当为符号位时,先判断当前符号是否为符号位-/+
if ("-".equals(cur) || "+".equals(cur)){
//判断是否位于字符串第一位,或者位于左括号后,往结果集中加入0
//因为加入0做数字进入计算,则可以把符号位当做运算符号计算,例如 (-35) === (0-35)
if (i == 0 || "(".equals(list.get(i-1))){
resList.add("0");
}
}
//当为符号位时,判断当前符号与栈顶符号的优先级,
//1、若当前优先级小于等于栈顶优先级则,遍历符号栈,将元素出栈直到不满足该条件,再将当前符号位cur压入栈中
//2、若当前优先级大于栈顶优先级则直接压入栈中
while (stack.size() != 0 && !"(".equals(stack.peek()) && level(cur) <= level(stack.peek())){
resList.add(stack.pop());
}
stack.push(cur);
}
}
//遍历符号栈,将剩余符号加入结果集
while (stack.size()!=0){
resList.add(stack.pop());
}
return resList;
}
/**
* 后缀表达式进行计算
* 1、遍历后缀表达式
* 2.1、若为数字,则直接push到栈中
* 2.2、若为符号位,则取出栈中的 栈顶 和 次栈顶位,使用该符号进行计算,将计算结果push到栈中
* 3、直到遍历完毕,取出栈内的栈顶元素即为最终结果
* @param list list
* @return int
*/
public static int calculate(List<String> list) {
//创建一个栈做中间结果存放
Stack<String> stack = new Stack<>();
//遍历后缀表达式
for (String item : list) {
if (isNumber(item)){
stack.push(item); //若为数字,则直接push到栈中
}else {
//若为符号位,则取出栈中的 栈顶 和 次栈顶位,使用该符号进行计算,将计算结果push到栈中
int num1 = Integer.parseInt(stack.pop());
int num2 = Integer.parseInt(stack.pop());
int res = 0;
if ("+".equals(item)){
res = num2 + num1;
}else if ("-".equals(item)){
res = num2 - num1;
}else if ("*".equals(item)){
res = num2 * num1;
}else if ("/".equals(item)){
res = num2 / num1;
}
stack.push(String.valueOf(res));
}
}
//直到遍历完毕,取出栈内的栈顶元素即为最终结果
return Integer.parseInt(stack.pop());
}
/**
* 判断符号优先级
*/
public static int level(String a){
if ("+".equals(a) || "-".equals(a)){
return 0;
}else if ("*".equals(a) || "/".equals(a)){
return 1;
}else {
throw new RuntimeException("符号不存在");
}
}
/**
* 判断是否为数字
*/
public static boolean isNumber(String a){
return String.valueOf(a).matches("(-?|\\+?)\\d+");
}
/**
* 去除空格
*/
public static String replaceSpace(String s){
return s.replaceAll("\\s","");
}