首先声明一下我的这个计算器只能计算加减乘除(除法会丢失精度,因为我限制的int,你可以自己试着写个double的),几位数都行,但是只能是正整数和0,不能有括号自然也不能写负数,但是首位允许写负数。先记录一下,以后有机会再给这个计算器升级。
如果不明白原理,推荐去bilibili搜索Java数据结构,有一个老师原理讲的很好,但是代码有点拉,所以以下的代码是我参照他的算法思想自己写的,因为对Java的一些写法不是很了解,写的途中查了很多资料,一共花了一下午的时间,总的来说这个东西不简单,写的时候发现了好多好多bug光是调试就花了我一半以上的时间,为什么这篇文章解释的这么详细,还不是因为过程的艰辛,简单的话我就直接上代码了连注释都没有。
代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class CalcDemo {
public static void main(String[] args) {
StackCalc calc = new StackCalc();
System.out.println(calc.comput("-10/2+9+9+1*1-1"));
}
}
class StackCalc {
Stack<Integer> integer_stack = new Stack<>();
Stack<Character> symbol_stack = new Stack<>();
//优先级判断函数
public int precedence(char chr) {
//因为我人为限制4个符号,这里就简单写了
if (chr == '*' || chr == '/') {
return 1;
} else {
return 0;
}
}
//运算函数
public int operation(int a, int b, char c) {
// switch (c) {
// case '+':
// return b + a;//-号都被我换成+号了
// case '*':
// return b * a;
// case '/':
// return b / a;//这里要格外注意a与b的顺序,千万不要弄反了
// default:
// return -1;//如果不加default它直接不让你运行
// }
//原本我写的是普通的swith IJ给我标黄告诉我可以用增强swith替换,哎,又学到了
return switch (c){
case '+'->b+a;//-号都被我换成+号了
case '*'->b*a;
case '/'->b/a;//这里要格外注意a与b的顺序,千万不要弄反了
default -> -1;//如果不加default它直接不让你运行
};
}
public int comput(String str) {
//split方法使程序能运算多位数
String[] str_lst = str.split("[+\\-*/]");//减号需要进行转义
//下方代码使我们能再开头位置输入负数
//比较str_lst[i]的值是否是空字符串如果是就替换成0,原本我写的是==,但是java说比较字符串是否相等要用equals
if (str_lst[0].equals("")) {
str_lst[0] = "0";
}
//创建一个数字列表
//数字列表永远比字符列表多一个,栈中也是一样
List<Integer> integer_lst = new ArrayList<>();
//添加数字
for (String i : str_lst
) {
integer_lst.add(Integer.parseInt(i));
}
//创建一个字符列表
List<Character> symbol_lst = new ArrayList<>();
//添加符号
int n = 0;
for (char i : str.toCharArray()
) {
if (i < 48 || i > 57) {
//特别说明一下为什么要把-换成+,如果不换计算结果会出现偏差,一开始我想了好久也没想到原因,后来我通过debug调试发现了这个问题
// 第一个减号后面的所有+-会隐性当作-+进行计算,由于不想更改下方算法,所以只能再前面进行处理了,如果你有更好的办法可以告诉我
if (i == '-') {
integer_lst.set(n + 1, -integer_lst.get(n + 1));
symbol_lst.add('+');
} else {
symbol_lst.add(i);//0-9的ascii码是48-57,我之前写成56一输入9就报错,害得我调了半天。。。
}
n++;
}
}
int j = 0;
int i = 0;
while (true) {
//第一个if添加数字
if (j != integer_lst.size()) {
integer_stack.add(integer_lst.get(j));
j++;
}
//第二个if添加符号
if (i != symbol_lst.size()) {
if (symbol_stack.empty()) {
symbol_stack.add(symbol_lst.get(i));
} else {
//要添加的符号优先级比前一个小就先把前面的算出来删掉再把结果入栈,再添加新符号,这里我用的是小于等于,因为我这里除法会丢失精度,所以尽量保证最终结果的精度吧。。。
if (precedence(symbol_lst.get(i)) <= precedence(symbol_lst.get(i - 1))) {
integer_stack.add(operation(integer_stack.pop(), integer_stack.pop(), symbol_stack.pop()));
symbol_stack.add(symbol_lst.get(i));
}
//如果优先级大直接添加就完了
else {
symbol_stack.add(symbol_lst.get(i));
}
}
i++;
}
//else与最近的if联立,理论上与无论与上方哪个if联立都没问题
else {
//下方条件是不为空带!,这个小bug卡了我10分钟
//将栈中剩余的全部进行计算直到栈中只剩下一个数就是最终结果
while (!symbol_stack.empty()) {
integer_stack.add(operation(integer_stack.pop(), integer_stack.pop(), symbol_stack.pop()));
}
return integer_stack.pop();
}
}
}
}
最后,这个代码完全是我按照自己的想法一个一个敲出来的,没有参照任何人,所以不敢保证完全没有问题,如果你在测试的时候发现了问题,一定要告诉我,非常感谢!