用Java实现简单计算器(新手向)
需求:用java实现简易计算器,包含加减乘除和括号功能。
分析:这是一道较常规的java试题,算术运算按顺序倒是好办,但是加上括号就不一样了,比如:5*(4+3),就得先算括号里面的(4+3)再进行括号外的乘法运算。
我们这里可以使用两个栈:一个存放数字,一个存放符号,以及一个运算符优先级表。
先弄两个栈
public static final Stack<Integer> DIGITALSTACK = new Stack<>(); // 数字栈
public static final Stack<Character> SYMBLESTACK = new Stack<>(); // 运算符栈
一个栈存放数字,一个存放运算符。
然后弄一个二维表存放运算符优先级顺序
我们就可以将栈顶运算符和当前遍历到的运算符对照这个表进行比较。
ps:‘#’是我们自己加进去的(当然用其他符号也可(~ ̄▽ ̄)~),我们要先把‘#’,压入符号栈中,作用是可以与第一个运算符进行比较。
/*
* 运算符优先级表
* 0 : 栈顶运算符弹出
* 1 : 当前运算符入栈
* -1 : 操作数和运算符弹出进行运算后入栈
*/
public static final int[][] TABLE= {
/* # + - * / ( ) 当前运算符 */
/* # */ { 0, 1, 1, 1, 1, 1, 0 },
/* + */ {-1,-1,-1, 1, 1, 1,-1 },
/* - */ {-1,-1,-1, 1, 1, 1,-1 },
/* * */ {-1,-1,-1,-1,-1, 1,-1 },
/* / */ {-1,-1,-1,-1,-1, 1,-1 },
/* ( */ { 0, 1, 1, 1, 1, 1, 0 },
/* ) */ { 0, 0, 0, 0, 0, 0, 0 },
/* 栈顶运算符 */
};
这里0表示:将栈顶运算符弹出
1:将当前运算符入栈
-1:将数字栈的两个数字出栈,符号栈的栈顶运算符出栈,运算得出结果后push进数字栈。
正式开工
public int calculate(String str) {
str += '#';
SYMBLESTACK.push('#');
int length = str.length();
boolean flag = false; // 判断是否为连续数字 (上一个是否为数字)
for(int i = 0; i < length; i++) {
char c = str.charAt(i);
if(Character.isDigit(c)) { // 当前字符为数字
if(flag) { // 上一字符为数字
int t = DIGITALSTACK.pop();
t = t * 10 + c - '0';
DIGITALSTACK.push(t);
}else {
DIGITALSTACK.push(c - '0');
flag = true;
}
}else { // 当前字符为符号
char pre = SYMBLESTACK.peek();
char now = c;
switch(TABLE[changeDig(pre)][changeDig(now)]) {
case 0 : SYMBLESTACK.pop(); break;
case 1 : SYMBLESTACK.push(c); break;
case -1 :
i--; // 退一位
int num = yunSuan(DIGITALSTACK.pop(),DIGITALSTACK.pop(),SYMBLESTACK.pop());
DIGITALSTACK.push(num);
break;
default : break;
}
flag = false;
}
}
return DIGITALSTACK.pop();
}
我们先把原传入的字符串后面加个‘#’,目的是可以与开始push进操作符栈的‘#’进行比较并弹出。
由于我们是按照字符串一个一个字符去遍历的,当我们遇到连续数字时,例如12,我们的做法是先把1入栈,然后遍历到2的时候,判断上一字符串是否为数字,若是,则把1弹出,乘10,加2,再把得到的12入栈,就ok啦( ̄▽ ̄)。
再贴上工具类
/*
* 将字符转换为二维表的下标
*/
private int changeDig(char c) {
int dig = 0;
switch(c) {
case '#' : dig = 0; break;
case '+' : dig = 1; break;
case '-' : dig = 2; break;
case '*' : dig = 3; break;
case '/' : dig = 4; break;
case '(' : dig = 5; break;
case ')' : dig = 6; break;
default : break;
}
return dig;
}
/*
* 运算
* 注意出入栈顺序
*/
private int yunSuan(int numOne, int numTwo, char c) {
int result = 0;
switch(c) {
case '+' : result = numTwo + numOne; break;
case '-' : result = numTwo - numOne; break;
case '*' : result = numTwo * numOne; break;
case '/' : result = numTwo / numOne; break;
}
return result;
}
至此,就算基本完成啦( •̀ ω •́ )✧
完整代码贴贴
public class Calculate {
/*
* 运算符优先级表
* 0 : 栈顶运算符弹出
* 1 : 当前运算符入栈
* -1 : 操作数和运算符弹出进行运算后入栈
*/
public static final int[][] TABLE= {
/* # + - * / ( ) 当前运算符 */
/* # */ { 0, 1, 1, 1, 1, 1, 0 },
/* + */ {-1,-1,-1, 1, 1, 1,-1 },
/* - */ {-1,-1,-1, 1, 1, 1,-1 },
/* * */ {-1,-1,-1,-1,-1, 1,-1 },
/* / */ {-1,-1,-1,-1,-1, 1,-1 },
/* ( */ { 0, 1, 1, 1, 1, 1, 0 },
/* ) */ { 0, 0, 0, 0, 0, 0, 0 },
/* 栈顶运算符 */
};
public static final Stack<Integer> DIGITALSTACK = new Stack<>(); // 数字栈
public static final Stack<Character> SYMBLESTACK = new Stack<>(); // 运算符栈
public int calculate(String str) {
str += '#';
SYMBLESTACK.push('#');
int length = str.length();
boolean flag = false; // 判断是否为连续数字 (上一个是否为数字)
for(int i = 0; i < length; i++) {
char c = str.charAt(i);
if(Character.isDigit(c)) { // 当前字符为数字
if(flag) { // 上一字符为数字
int t = DIGITALSTACK.pop();
t = t * 10 + c - '0';
DIGITALSTACK.push(t);
}else {
DIGITALSTACK.push(c - '0');
flag = true;
}
}else { // 当前字符为符号
char pre = SYMBLESTACK.peek();
char now = c;
switch(TABLE[changeDig(pre)][changeDig(now)]) {
case 0 : SYMBLESTACK.pop(); break;
case 1 : SYMBLESTACK.push(c); break;
case -1 :
i--; // 退一位
int num = yunSuan(DIGITALSTACK.pop(),DIGITALSTACK.pop(),SYMBLESTACK.pop());
DIGITALSTACK.push(num);
break;
default : break;
}
flag = false;
}
}
return DIGITALSTACK.pop();
}
/*
* 将字符转换为二维表的下标
*/
private int changeDig(char c) {
int dig = 0;
switch(c) {
case '#' : dig = 0; break;
case '+' : dig = 1; break;
case '-' : dig = 2; break;
case '*' : dig = 3; break;
case '/' : dig = 4; break;
case '(' : dig = 5; break;
case ')' : dig = 6; break;
default : break;
}
return dig;
}
/*
* 运算
* 注意出入栈顺序
*/
private int yunSuan(int numOne, int numTwo, char c) {
int result = 0;
switch(c) {
case '+' : result = numTwo + numOne; break;
case '-' : result = numTwo - numOne; break;
case '*' : result = numTwo * numOne; break;
case '/' : result = numTwo / numOne; break;
}
return result;
}
}
骚微测试下
public class MyTest {
public static void main(String[] args) {
Calculate cal = new Calculate();
String str = "12*(8-4)+36";
System.out.println(str+"的运算结果是:");
System.out.println(cal.calculate(str));
}
}
完工。
其实应该判断字符串是否为正确运算式的,偷懒(●’◡’●)