QT-计算器核心解析算法
1.分离算法
将中缀表达式进行数字和运算符的分离
以符号作为标志对表达式中的字符逐个访问
- 初始累计变量num为空,遍历字符串每个字符
- 若遇到数字或小数点(即当前符号是数字的一部分),累加到num变量,并用pre变量记录当前符号(用来判断正负号)
- 若遇到其它符号(+, -, *, / , ( , ) ,+, -)
- 先看num变量,若有值,num的值放入队列,清空num
- 若为正负号,累计到num变量(流程能走到这说明num无值)
- 否则当前字符(即运算符或括号)入队列
- pre记录当前字符
- 遍历结束后若num不为空,入队列(遍历的最后一个字符是数字还没机会入队列)
QQueue<QString> QCalculatorDec::split(const QString& exp) { QQueue<QString> ret; QString num = ""; QString pre = ""; for(int i=0; i<exp.length(); i++) { if( isDigitOrDot(exp[i]) ) { num += exp[i]; pre = exp[i]; } else if( isSymbol(exp[i]) ) { if( !num.isEmpty() ) { ret.enqueue(num); num.clear(); } if( isSign(exp[i]) && ((pre == "") || (pre == "(") || isOperator(pre)) ) { num += exp[i]; } else { ret.enqueue(exp[i]); } pre = exp[i]; } } if( !num.isEmpty() ) { ret.enqueue(num); } return ret; }
区分正负号和加减号准则:正负号 + 和 - 在表达式的第一个位置、括号后的 + 和 - 、运算符后的 + 和 -
中缀转后缀算法
栈主要是用来保存中缀表达式中的运算符,左右括号就是在转换过程中被丢弃
伪代码
如何确保表达式中的括号能够左右匹配
-括号匹配算法
bool QCalculatorDec::match(QQueue<QString>& exp) { bool ret =true; int len = exp.length(); QStack<QString> stack; for(int i=0;i<len;i++) { if(isLeft(exp[i])) stack.push(exp[i]); else if(isRight(exp[i])) { if(!stack.empty() && isLeft(stack.top())) { stack.pop(); } else { ret = false; break; } } } return ret; }
转换
bool QCalculatorDec::transform(QQueue<QString>& exp,QQueue<QString>& output) { bool ret = match(exp); QStack<QString> stack; output.clear(); while(ret && !exp.isEmpty()) { QString e = exp.dequeue(); if(isNumber(e)) { output.enqueue(e); } else if(isOperator(e)) { while(!stack.isEmpty() && (priority(e)<=priority(stack.pop()))) { output.enqueue(stack.pop()); } stack.push(e); } else if(isLeft(e)) { stack.push(e); } else if(isRight(e)) { while(!stack.isEmpty() && !isLeft(stack.top())) { output.enqueue(stack.pop()); } if(!stack.isEmpty()) { stack.pop(); } } else { ret =false; } } while(!stack.isEmpty())//返回之前有必要再次检查栈中是否还有元素 { output.enqueue(stack.pop()); } if(!ret) { output.clear(); } return ret; }
后缀表达式的计算
与数学计算相关的算法都需要考虑除0的情况
注意:若是浮点运算,避免代码中直接与0做相等比较