问题描述
实现一个基本的计算器来计算一个简单的字符串表达式的值。注意事项如下: - 输入是一个字符串表达式(可以假设所给定的表达式都是有效的) - 字符串表达式可以包含的运算符号为:左括号 (
, 右括号 )
, 加号 +
, 减号 -
- 可以包含的数字为:非负整数(< 10) - 字符串中不包含空格 - 处理除法 case 的时候,可以直接省略小数部分结果,只保留整数部分参与后续运算 - 请不要使用内置的库函数 eval
思路
首先明确一点,四则运算中乘法和除法的优先级是最高的,所以要优先考虑乘除,加减运算留到最后再去算,加上表达式可以有括号,在将乘除运算完过后要优先把括号中的式子的值计算出来。 那么面对一个带有括号的四则运算表达式,我们怎么进行计算呢?对我们人来说这是很简单的,按照规则一点点算就是了,可是计算机只能从前往后看这个表达式,它是呆板的,怎么把后面的优先级高的计算完再去找前面的优先级低的呢?我们可以利用广为人知的数据结构-栈,来分别存储数字和运算符
ini
static Stack<Character> cal=new Stack<>();
static Stack<Integer> number=new Stack<>();
先从前往后遍历一遍表达式,
遇到数字则直接压入数字栈中
遇到乘除运算的时候我们不能直接就取后面的数字来与前面的数组进行运算,因为当遇到4*(2+3*2)这种表达式时,我们只会取到一个左括号,无法计算,所以我们直接将其入栈
遇到加减运算时,我们也不能直接进行计算,因为无法确定两边的数字是否被乘除所占用,或是一个没有被计算完毕的括号表达式,所以也是直接入栈,但是这个时候我们可以看一看运算符栈中是否有乘除运算符,如果有的话,从数字栈中取出两个数进行相应的运算然后再将数字入栈
ini
switch (k) {
case '(':
case '/':
case '*':
cal.add(k);
break;
case '+':
if(cal.size()>0){
char x=cal.lastElement();
if(x=='*'){
cal.pop();
int firstnum=number.lastElement();
number.pop();
int secondnum=number.lastElement();
number.pop();
number.add(firstnum*secondnum);
}else if(x=='/'){
cal.pop();
int firstnum=number.lastElement();
number.pop();
int secondnum=number.lastElement();
number.pop();
number.add(secondnum/firstnum);
}
}
cal.add(k);
break;
case '-':
if(cal.size()>0){
char x=cal.lastElement();
if(x=='*'){
cal.pop();
int firstnum=number.lastElement();
number.pop();
int secondnum=number.lastElement();
number.pop();
number.add(firstnum*secondnum);
}else if(x=='/'){
cal.pop();
int firstnum=number.lastElement();
number.pop();
int secondnum=number.lastElement();
number.pop();
number.add(secondnum/firstnum);
}
}
cal.add(k);
break;
default:
number.add(k-48);//小于10的单个字符直接入栈
break;
}
}
如果遇到括号,遇到左括号我们不做任何处理,直接将其入栈,然后继续按照上面的规则进行运算即可,如果遇到的是右括号,我们就需要把这个括号表达式的值给算出来。
遇到右括号后循环的从运算符栈中取运算符,每次取两个数字进行相应的运算(这个时候不考虑优先级了,因为如果有加减运算那么它们前面的乘除运算就一定被计算完毕,如果没有加减运算就不用考虑优先级了),直到取到左括号为止,然后继续遍历表达式
scss
char kk=cal.lastElement();
cal.pop();
while(kk!='('){
Traverse(kk);//不考虑优先级进行运算
kk=cal.lastElement();
cal.pop();
}
利用上面这些操作循环遍历一次表达式,剩下的运算就不用考虑优先级了,不断的从运算符栈中取运算符进行计算即可,最后数字栈中只剩一个数,直接取走返回答案即可
下面放一下完整的代码,有兴趣的可以复制下来去测试着玩一下,如上分析如有错误敬请各位指出
ini
public class Main {
static Stack<Character> cal=new Stack<>();
static Stack<Integer> number=new Stack<>();
public static int solution(String expression) {
int length=expression.length();
for(int i=0;i<length;i++){
char k=expression.charAt(i);
if(k==')'){
char kk=cal.lastElement();
cal.pop();
while(kk!='('){
Traverse(kk);
kk=cal.lastElement();
cal.pop();
}
}else{
switch (k) {
case '(':
case '/':
case '*':
cal.add(k);
break;
case '+':
if(cal.size()>0){
char x=cal.lastElement();
if(x=='*'){
cal.pop();
int firstnum=number.lastElement();
number.pop();
int secondnum=number.lastElement();
number.pop();
number.add(firstnum*secondnum);
}else if(x=='/'){
cal.pop();
int firstnum=number.lastElement();
number.pop();
int secondnum=number.lastElement();
number.pop();
number.add(secondnum/firstnum);
}
}
cal.add(k);
break;
case '-':
if(cal.size()>0){
char x=cal.lastElement();
if(x=='*'){
cal.pop();
int firstnum=number.lastElement();
number.pop();
int secondnum=number.lastElement();
number.pop();
number.add(firstnum*secondnum);
}else if(x=='/'){
cal.pop();
int firstnum=number.lastElement();
number.pop();
int secondnum=number.lastElement();
number.pop();
number.add(secondnum/firstnum);
}
}
cal.add(k);
break;
default:
number.add(k-48);//小于10的单个字符直接入栈
break;
}
}
}
while(cal.size()>0){
char kk=cal.lastElement();
cal.pop();
Traverse(kk);
}
return number.lastElement();
}
public static void Traverse(char kk){
int firstnum=number.lastElement();
number.pop();
int secondnum=number.lastElement();
number.pop();
int num=0;
switch (kk) {
case '+':
num=firstnum+secondnum;
break;
case '-':
num=secondnum-firstnum;
break;
case '*':
num=secondnum*firstnum;
break;
case '/':
num=secondnum/firstnum;
break;
}
number.add(num);
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution("1+1") == 2);
System.out.println(solution("3+4*5/(3+2)") == 7);
System.out.println(solution("4+2*5-2/1") == 12);
System.out.println(solution("(1+(4+5+2)-3)+(6+8)") == 23);
System.out.println("请输入一个10以内的加减乘除计算公式");
Scanner scan=new Scanner(System.in);
String s=scan.nextLine();
System.out.println("结果为"+solution(s));
}
}