1 思路如下
-
通过一个index索引值来 遍历算式表达式;
-
使用两个栈来模拟。一个为数字栈,一个为符号栈;
-
如果为数字,则入数字栈;
-
如果为符号,则分以下情况:
4.1 符号栈为空:直接入符号栈;
4.2 符号栈不为空:将当前符号与符号栈中的栈顶元素进行优先级比较。 如果当前操作符号优先级小于栈顶元素,则取出符号栈的栈顶元素,并从数字栈取出两个数进行运算,得到数字结果入数字栈,并将当前操作符入符号栈。如果当前的操作符的优先级大于符号栈栈顶元素,则直接入符号栈。
-
当表达式扫描完毕,则顺序从数字栈和符号栈取出对应的数字和符号进行计算,将结果继续存入数字栈,直到符号栈为空;
-
此时,数字栈只剩下了计算的结果, 该结果即为表达式的值。
栈的内容可以参考我的博客链接:Java数据结构:栈与综合计算器的实现(图解+完整代码)
以3+2*6-2为例:
- 先将3入数字栈
+
入符号栈
- 2入数字栈
- 遇到了
*
,将其与符号栈的栈顶元素+
比较,*
的优先级更高,因此,*
直接入符号栈
- 6 入数字栈
-
与符号栈栈顶*
进行比较,-
优先级低,因此,将符号栈的栈顶*
出栈。数字栈依次出栈两个数6、2,计算2*6的值为12,并将12入数字栈,当前操作符-
入符号栈
- 2 入栈,至此,表达式遍历完成。下面将要开始依次取值计算,直到符号栈为空。
- 将2、12从数字栈取出,将
-
从符号栈取出,计算12-2的值10,入数字栈
- 依次将10、3从数字栈出栈,
+
从符号栈取出,并计算3+10的值为13,13入数字栈。此时,符号栈为空,运算到此为止,13即为表达式的结果。
2 注意事项
需要考虑括号,当符号栈为空或者栈顶为左括号的时候,符号直接入栈。当当前的元素为右括号的时候,需要依次将符号从符号栈中弹出,进行对应数字栈的计算,将计算结果压入数字栈。 直到遇到左括号为止,将左括号出栈。
3 完整代码
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 返回表达式的值
* @param s string字符串 待计算的表达式
* @return int整型
*/
public int solve (String s) {
// write code here
//利用双栈去模拟,一个数字栈,一个符号栈
int res = 0; //存储结果
Stack<String> numStack = new Stack<>();
Stack<String> operationStack = new Stack<>();
//获取表达式的list
List<String> list = toInfixExpressionList(s);
//遍历list
String str = "";
for(int i = 0; i < list.size(); i++){
//如果是数字则入数字栈
str = list.get(i);
if(str.matches("\\d+")){
numStack.push(str);
}else{
//如果是符号,则入符号栈
//对于左括号,直接入符号栈
if(operationStack.isEmpty() || str.equals("(")){
operationStack.push(str);
}else if(str.equals(")")){
//如果是右括号,则依次弹出操作符,并从数栈弹出两个数进行计算,后压栈
while(!operationStack.peek().equals("(")){
String operation = operationStack.pop();
int num1 = Integer.valueOf(numStack.pop());
int num2 = Integer.valueOf(numStack.pop());
res = calculate(num1, num2, operation);
numStack.push(String.valueOf(res));
}
//将匹配的左括号出栈
operationStack.pop();
}else{
//如果是符号,则将当前符号与符号栈栈顶元素进行判断
//如果优先级小于等于栈顶元素,则出栈运算符,并取出两个数进行计算,压栈
if ((!operationStack.peek().equals("(") && !operationStack.peek().equals(")"))
&& priority(str) <= priority(operationStack.peek())){
int num1 = Integer.parseInt(numStack.pop());
int num2 = Integer.parseInt(numStack.pop());
String oper = operationStack.pop();
res = calculate(num1, num2, oper);
//将运算结果入数栈
numStack.push(String.valueOf(res));
//将当前的操作符入符号栈
operationStack.push(str);
}else {
//栈顶元素优先级小于当前运算符,或者为括号
operationStack.push(str);
}
}
}
}
//表达式扫描完毕过后,顺序的从数栈和符号栈取出对应的数字和符号进行运算
//最后数栈只剩的一个数字为结果
//也可以判断符号栈是否为空,如果为空则说明数栈只剩一个数
while (numStack.size() > 1){
int num1 = Integer.parseInt(numStack.pop());
int num2 = Integer.parseInt(numStack.pop());
String oper = operationStack.pop();
res = calculate(num1, num2, oper);
numStack.push(String.valueOf(res));
}
//打印结果
return Integer.valueOf(numStack.pop());
}
//返回运算符号的优先级,返回数字越大,优先级越大
public int priority(String operation){
if ("*".equals(operation) || "/".equals(operation)){
return 1;
}else if ("-".equals(operation) || "+".equals(operation)){
return 0;
}else {
return -1;
}
}
//将中缀表达式分数字和运算符依次存入List中,便于遍历
public List<String> toInfixExpressionList(String s){
List<String> list = new ArrayList<>();
char c = ' ';//存储每一位String字符
for(int i = 0; i < s.length(); ){
if((c=s.charAt(i)) < '0' || (c=s.charAt(i)) > '9'){//是运算符的情况
list.add(c+"");
i++;
}else{
//数字处理拼接
String str = "";
while(i < s.length() && (c=s.charAt(i)) >= '0' && (c=s.charAt(i)) <= '9'){
str += c;
i++;
}
list.add(str);
}
}
return list;
}
//四则运算
public int calculate(int num1, int num2, String operation){
int res = 0;
switch(operation){
case "+":
res = num2 + num1;
break;
case "-":
res = num2 - num1;
break;
case "*":
res = num2 * num1;
break;
case "/":
res = num2 / num1;
break;
default:
break;
}
return res;
}
}