2021SC@SDUSC
? ? ? ? 这篇研究BaseCalculator类中对中缀表达式的计算
? ? ? ? 使用的是基于堆栈的算法,有一个元素类用于表示后缀表达式中的每一个元素
private class Ele {
public boolean isNum;
public double o;
public char op;
public Ele(double o,boolean isNum){
this.isNum=isNum;
this.o=o;
}
public Ele(char op,boolean isNum) {
this.isNum = isNum;
this.op = op;
}
}
用于进行后缀表达式计算。
? ? ? ? 判断是否是数字
private boolean isNum(char c){
return (c-'0'>=0&&c-'0'<=9)||c=='.';
}
? ? ? ? operate方法提供简单的四则和E运算
private double operate(double a, char oper, double b) {
switch (oper) {
case '+':
return a + b;
case '-':
return a - b;
case '×':
return a * b;
case '/':
if (b == 0) {
return Double.MAX_VALUE; //处理异常
}
return a / b;
case 'E':
return Double.parseDouble(String.valueOf(a+"E"+(int)b));
default:
return 0;
}
}
? ? ? ? 接下来就是关键的运算了
????????先初始化一个队列和数字栈,字符栈
Stack<Character> operStack = new Stack<>();
Queue<Ele> eleQueue = new LinkedList<>();
Stack<Double> numStack = new Stack<>();
? ? ? ? 中缀表达式转后缀表达式
- 初始化两个栈:运算符栈s1和储存后缀表达式的队列s2; 从左至右扫描中缀表达式; 遇到操作数时,将其压入s2;
- 遇到运算符时,比较其与s1栈顶运算符的优先级: 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
- 否则,若优先级比栈顶运算符的高,也将运算符压入s1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
- 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较; 遇到括号时:
- 如果是左括号“(”,则直接压入s1;
- 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
- 重复步骤2至5,直到表达式的最右边; 将s1中剩余的运算符依次弹出并压入s2;
- 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)
int firstIndex = 0;
int i=0;
while (i < math.length()) {
char charOfMath = math.charAt(i);
if (charOfMath == '(') {
operStack.push(charOfMath);
i++;
} else if (charOfMath == ')') {
while (operStack.peek() != '(') {
eleQueue.offer(new Ele(operStack.pop(), false));
}
operStack.pop();
i++;
}else if(isNum(charOfMath)){
firstIndex=i;
while (++i<math.length()&&isNum(math.charAt(i)));
double num;
try {
num = Double.parseDouble(math.substring(firstIndex, i));
} catch (NumberFormatException e) {
return Double.MAX_VALUE;
}
eleQueue.offer(new Ele(num,true));
}else{
//说明-是单目运算符
if (charOfMath == '-') {
if (i == 0) {
firstIndex=0;
while (++i<math.length()&&isNum(math.charAt(i)));
double num;
try {
num = Double.parseDouble(math.substring(firstIndex, i));
} catch (NumberFormatException e) {
return Double.MAX_VALUE;
}
eleQueue.offer(new Ele(num,true));
continue;
} else if (math.charAt(i - 1)=='(') {
//表示这是一个单目运算符
firstIndex=i;
while (++i<math.length()&&isNum(math.charAt(i)));
double num;
try {
num = Double.parseDouble(math.substring(firstIndex, i));
} catch (NumberFormatException e) {
return Double.MAX_VALUE;
}
eleQueue.offer(new Ele(num,true));
continue;
}
}
while (operStack.size() >= 0) {
if (operStack.size() == 0 || operStack.peek() == '(') {
operStack.push(charOfMath);
break;
} else {
if (operMap.get(operStack.peek()) < operMap.get(charOfMath)) {
operStack.push(charOfMath);
break;
} else {
eleQueue.offer(new Ele(operStack.pop(), false));
}
}
}
i++;
}
}
while (operStack.size()>0){
eleQueue.offer(new Ele(operStack.pop(),false));
}
? ? ? ? 最后检查后缀表达式进行计算
? ? ? ? 从左到右扫描后缀表达式,如果是操作数,就压入操作数栈s3,如果是操作符,就连续弹出两个操作数(注意:后弹出的为第一操作数,先弹出的为第二操作数),然后进行操作符的操作,将新生成的操作数压入栈中,反复直到后缀表达式扫面完毕,栈s3中只存在一个数,就是最终结果。
while (eleQueue.size() > 0) {
if (eleQueue.element().isNum) {
numStack.push(eleQueue.poll().o);
} else {
char op = eleQueue.poll().op;
double second= numStack.pop();
double first = numStack.pop();
numStack.push(operate(first, op, second));
}
}
return numStack.peek();
|