一、使用栈实现中缀表达式的计算
思路
- 建立两个栈,一个用于存放数值number,一个用于存放运算符chs
- 遇到数值,则直接将数值压入number中
- 遇到运算符,这里不包括括号,如果chs中栈顶的运算符优先级大于等于当前运算符,则在number中栈顶弹出两个数值,chs栈顶弹出一个运算符进行计算,并将计算结果压入栈中,重复该操作知道chs栈顶运算符优先级小于当前运算符优先级
- 运算符优先级小于栈顶优先级,直接压入chs
- 遇到(,直接压入chs
- 遇到),在number中栈顶弹出两个数值,chs栈顶弹出一个运算符进行计算,重复该操作知道chs栈顶为(,并将 ( 弹出栈
- 最终number和chs全部数据出栈,计算得到最终结果,number剩下的最后一个值就是为最终结果
代码
public class StackDemo {
static Stack<Integer> number = new Stack<>();
static Stack<Character> chs = new Stack<>();
public static int priotity(char ch) {
if (ch=='+' || ch=='-') {
return 1;
} else if (ch=='*' || ch=='/') {
return 2;
} else if (ch=='(' || ch==')') {
return -1;
}
return 0;
}
public static int cal(int a, int b, char ch) {
if (ch=='+') {
return a+b;
} else if (ch=='-') {
return a-b;
} else if (ch=='*') {
return a*b;
} else if (ch=='/') {
return a/b;
}
return 0;
}
public static void getAns() {
int t1 = number.pop();
int t2 = number.pop();
int ans = cal(t2, t1, chs.pop());
number.push(ans);
}
public static void calRes(String str) {
char a[] = str.toCharArray();
for(int i=0; i<a.length; i++) {
int temp = priotity(a[i]);
if (temp==0) {
int num = a[i] - 48;
int j = i+1;
for(j=i+1; j<a.length; j++) {
if (priotity(a[j])==0) {
num = num*10 + (a[j] - 48);
} else {
break;
}
}
i = j-1;
number.push(num);
} else {
if (chs.isEmpty()) {
chs.push(a[i]);
} else if(a[i]==')') {
while(chs.peek()!='(') {
getAns();
System.out.println(number.peek());
}
chs.pop();
} else if (a[i]=='(') {
chs.push(a[i]);
} else {
int perOper = priotity(chs.peek());
if (perOper >= temp) {
getAns();
i--;
} else {
chs.push(a[i]);
}
}
}
}
while(!chs.isEmpty()) {
getAns();
}
System.out.println(str + " = " + number.pop());
}
public static void main(String[] args) {
String str = "1+2*4+(10-3*11+11)+60-9+8*6";
calRes(str);
}
}
二、中缀表达式转化为后缀表达式
思路
- 初始化两个栈:运算符栈 s1 和储存中间结果的栈 s2
- 从左至右扫描中缀表达式
- 遇到操作数时,将其压 s2
- 遇到运算符时,比较其与 s1 栈顶运算符的优先级:1).如果 s1 为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;2).否则,若优先级比栈顶运算符的高,也将运算符压入 s1;3).否则,将 s1 栈顶的运算符弹出并压入到 s2 中,再次转到(4.1)与 s1 中新的栈顶运算符相比较
- 遇到括号时:1) 如果是左括号“(”,则直接压入 s12) 如果是右括号“)”,则依次弹出 s1 栈顶的运算符,并压入 s2,直到遇到左括号为止,此时将这一对括号丢弃
- 重复步骤 2 至 5,直到表达式的最右边
- 将 s1 中剩余的运算符依次弹出并压入 s2
- 依次弹出 s2 中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
代码
public class InfixToPostfix {
static Stack<String> chs = new Stack<>();
static List<String> postfix = new ArrayList<String>();
public static int priotity(String ch) {
if (ch.equals("+") || ch.equals("-")) {
return 1;
} else if (ch.equals("*") || ch.equals("/")) {
return 2;
} else if (ch.equals("(") || ch.equals(")")) {
return -1;
}
return 0;
}
public static void solve(String str) {
String res[] = str.split("");
for(int i=0; i<res.length; i++) {
System.out.println(res[i]);
int temp = priotity(res[i]);
if (temp==0) {
String num = res[i];
int j = i+1;
for(j=i+1; j<res.length; j++) {
if (priotity(res[j])==0) {
num += res[j];
} else {
break;
}
}
i = j-1;
postfix.add(num);
} else {
if (res[i].equals("(")) {
chs.push(res[i]);
} else if (res[i].equals(")")) {
while(!chs.peek().equals("(")) {
postfix.add(chs.pop());
}
chs.pop();
} else if (chs.isEmpty()) {
chs.push(res[i]);
} else {
while(!chs.isEmpty() && priotity(chs.peek())>=temp) {
postfix.add(chs.pop());
}
chs.push(res[i]);
}
}
}
while(!chs.isEmpty()) {
postfix.add(chs.pop());
}
System.out.println("中缀表达式:" + str);
System.out.println("后缀表达式:" + postfix);
}
public static void main(String[] args) {
String str = "781+((2+303)*44)-512";
solve(str);
}
}
三、计算后缀表达式的值
思路
- 遍历中缀转化为后缀表达式的列表postfix
- 如果是数值,则加入数值栈中number
- 如果是运算符,则从number中栈顶弹出两个数值,并将计算结果压入栈中
- number剩下的最后一个值即为最终答案
代码
public static int cal(int a, int b, String ch) {
if (ch.equals("+")) {
return a+b;
} else if (ch.equals("-")) {
return a-b;
} else if (ch.equals("*")) {
return a*b;
} else if (ch.equals("/")) {
return a/b;
}
return 0;
}
public static void getAns(String oper) {
int t1 = number.pop();
int t2 = number.pop();
int ans = cal(t2, t1, oper);
number.push(ans);
}
public static void calPostfix() {
for(String str : postfix) {
if(str.matches("\\d+")) {
number.push(Integer.parseInt(str));
} else {
getAns(str);
}
}
System.out.println(number.pop());
}