社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
表达式的计算是指求诸如(34+2)*4*2+7
表达式的值,因为涉及到括号和算符优先级,如果直接进行计算比较麻烦,按照(34+2)*4*2+7
正常的顺序成为中缀表达式,在计算表达式式先转换为后缀表达式比较方便,(34+2)*4*2+7
的后缀表达式为34 2 + 4 * 2 * 7 +
。
求解表达式的过程有两步:
1、将表达式转换为后缀,
2、利用后缀求表达式值。
一、首先介绍将中缀表达式转换为后缀的算法:
首先定义运算符之间的优先级,每个运算符有两个优先级:栈(stack)内优先级,栈外优先级,分别用isp和icp表示。下面一张图是殷人昆版数据结构的优先级表,很准确。
优先级表可以简单的概括为,遇到’(‘进栈,遇到’)‘出栈,*和/优先级,以及+和/之间优先级自左到右,*/优先级大于+-优先级
在转换过程中设立操作符栈,如果读到的是数字直接输出,如果读到的是操作符,则考虑是否要进栈,如果读到的字符的栈外优先级大于栈顶的字符的栈内优先级,则进栈;否则栈顶操作符出栈并输出,再比较出栈操作后的栈顶元素的优先级,直到遇到一个栈顶元素栈内优先级大于读到的操作符的栈外的优先级,或者栈为空为止,最后将读到的操作符进栈。
一、下面具体介绍算法,假设当前读到的字符为ch
:
1、若ch是操作数直接输出,读入下一个字符到ch
2、若ch是操作符,判断ch的优先级icp(栈外优先级)和当前位于栈顶的操作符op的优先级isp(栈内优先级):
1)若icp(ch)>isp(op),令ch进栈,读入下一个字符ch.
2)若icp(ch)<isp(op),退栈并输出。
3)若icp(ch)=isp(ch),退栈但是不输出,因为是括号,只有括号才能相等。
结束。输出即为后缀表达式。
二、利用后缀求表达式值。
同样需要设置一个栈,以34 2 + 4 * 2 * 7 +
为例,遇到数字时进栈,遇到操作符时取出栈顶的两个数,并进行相应的运算,比如遇到+
,则计算34+2,并将34+2的结果重新放入栈顶。最后栈顶的数即为最终的运算结果。
下面是一个java代码实现, middleToPost()
函数将中缀转换为后缀,calculate()
函数利用后缀求值:
package leetCode;
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
//元素类,是为了防止数字大于10的情况,如34+2
class Ele{
public boolean isOp;
public double num;
public char op;
}
//将中缀转换为后缀,包含+ - ( ) * /数字
//规则:1、遇到数字输出 2、遇到操作符考虑是否进栈
//3、遇到“(”,进栈,遇到“)”,将操作符出栈,直到遇到“(”,且将后者出栈
public ArrayList<Ele> middleToPost(String s){
Stack<Ele> opStack = new Stack<Ele>();
s = s.replace(" ", "");
ArrayList<Ele> res = new ArrayList<Ele>();
for(int i=0;i<s.length();i++){
//getNext操作,寻找下一个有效的整数或操作符
char c = s.charAt(i);
Ele ele = new Ele();
if(c>'9'||c<'0'){
ele.isOp = true;
ele.op = c;
}else{
String str = c+"";
while(i+1<s.length() && s.charAt(i+1)<='9'&&s.charAt(i+1)>='0'){
str = str+s.charAt(i+1);
i++;
}
ele.isOp = false;
ele.num = Double.parseDouble(str);
}//end
if(!ele.isOp){
res.add(ele);
}else{
switch(ele.op){
case '(':
opStack.push(ele);break;
case ')':
while(opStack.peek().op!='('){
res.add(opStack.pop());
}
opStack.pop();
break;
case '/': // ‘/’ ‘*’处理方式一样
case '*':
if(opStack.isEmpty()){
opStack.push(ele);
}else{
while(!opStack.isEmpty() && (opStack.peek().op=='*' || opStack.peek().op=='/')){
res.add(opStack.pop());
}
opStack.push(ele);
}
break;
default: //处理 + -
if(opStack.isEmpty()){
opStack.push(ele);
}else{
while(!opStack.isEmpty()&&opStack.peek().op!='('){
res.add(opStack.pop());
}
opStack.push(ele);
}
}
}
}
while(!opStack.isEmpty()){
res.add(opStack.pop());
}
return res;
}
//利用后缀表达式求值
public int calculate(String s) {
ArrayList<Ele> eles = middleToPost(s);
Stack<Double> stack = new Stack<Double>();
double top = 0.0;
for(int i=0;i<eles.size();i++){
Ele e = eles.get(i);
if(e.isOp){
if(e.op=='+'){
top= stack.pop()+stack.pop();
}else if(e.op=='-'){
double after = stack.pop();
double before = stack.pop();
top = before-after;
}else if(e.op=='*'){
top = stack.pop()*stack.pop();
}else{
double after = stack.pop();
double before = stack.pop();
top = (int)before/(int)after;
}
stack.push(top);
}else{
stack.push(e.num);
}
}
return stack.peek().intValue();
}
public static void main(String[] args) {
Solution so = new Solution();
String s = "14/3*2";
ArrayList<Ele> list = so.middleToPost(s);
//输出后缀表达式
for(int i=0;i<list.size();i++){
if(list.get(i).isOp)
System.out.print(list.get(i).op+" ");
else
System.out.print(list.get(i).num+" ");
}
System.out.println();
//输出计算结果
System.out.println(so.calculate(s));
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!