这边文章来介绍该项目的计算引擎模块。
#ifndef CALCULATORDEC_H #define CALCULATORDEC_H #include <qt5/QtCore/QString> #include <qt5/QtCore/QStack> #include <qt5/QtCore/QString> #include "ICalculator.h" class CalculatorDec : public ICalculator { public: CalculatorDec(); ~CalculatorDec(); bool expression(const QString & exp); QString result(); private: QString calculate(const QString & exp); bool isDigit(char ch); bool isLeft(char ch); bool isDot(char ch); bool isRight(char ch); int judge(char c); double compute(char c,double a,double b); private: QString m_exp; QString m_result; }; #endif
bool expression(const QString & exp); QString result();
这两个方法是重写 ICalculator中的方法,当然也可以通过别的方式实现,我在这是为了更好的理解Virtual函数的思想。
下面是该类的具体实现
#include "QCalculatorDec.h" CalculatorDec::CalculatorDec() { m_exp = ""; m_result = ""; } CalculatorDec::~CalculatorDec() { } bool CalculatorDec::expression(const QString & exp) { bool ret = false; m_result = calculate(exp); ret = (m_result != "Error"); return ret; } QString CalculatorDec::result() { return m_result; } QString CalculatorDec::calculate(const QString & exp) { QString ret = "Error"; QByteArray ba = exp.toLatin1(); const char *str = ba.data(); QStack<double> stack_digit; QStack<char> stack_op; const char *p; for(p=str;*p;p++) { if(isDigit(*p)) { stack_digit.push(atof(p)); while(isDigit(*p)) p++; if(isDot(*p)) { p=p+1; while(isDigit(*p)) p++; } p--; // printf("%c ",*p); } else { if(stack_op.isEmpty() || isLeft(*p)) { stack_op.push(*p); continue; } else { if(isRight(*p)) { while(!isLeft(stack_op.top())) { char b1 = stack_op.pop(); double a1 = stack_digit.pop(); double a2 = stack_digit.pop(); stack_digit.push(compute(b1,a1,a2)); } stack_op.pop(); } else { if(!isLeft(stack_op.top())) { if(judge(*p)<=judge(stack_op.top())) { char b2 = stack_op.pop(); double a3 = stack_digit.pop(); double a4 = stack_digit.pop(); stack_digit.push(compute(b2,a3,a4)); p--; continue; } else { stack_op.push(*p); } } else { stack_op.push(*p); } } } } } while(!stack_op.isEmpty()) { char b3 = stack_op.pop(); double a5 = stack_digit.pop(); double a6 = stack_digit.pop(); stack_digit.push(compute(b3,a5,a6)); } double ret1 = stack_digit.pop(); ret = QString::number(ret1,'f',2); return ret; } bool CalculatorDec::isDigit(char ch) { if(ch>='0' && ch<='9') return true; else return false; } bool CalculatorDec::isLeft(char ch) { if(ch=='(') return true; else return false; } bool CalculatorDec::isDot(char ch) { if(ch=='.') return true; else return false; } bool CalculatorDec::isRight(char ch) { if(ch==')') return true; else return false; } int CalculatorDec::judge(char c) { int ret = 0; if(c=='+' || c=='-') ret = -1; if(c=='*' || c=='/') ret = 0; return ret; } double CalculatorDec::compute(char c,double a,double b) { double ret = 0; if(c=='+') ret = b+a; if(c=='-') ret = b-a; if(c=='*') ret = b*a; if(c=='/') ret = b/a; return ret; }
说一下算法设计思路,首先是用两个栈来存放数据和符号(数据栈和符号栈)。
算法(重点):
数字:数字无条件入栈
符号:
判断符号栈是否为空,如果为空,则无条件入栈
如果不为空,
当前符号如果为右括号:
一直去弹符号栈,直到弹出第一个左括号。
当前符号如果不为右括号:
判读栈顶元素是不是左括号
栈顶不是左括号
当前符号优先级 <= 栈顶元素的优先级,则计算。(出栈一个符号,出两个数字,先出栈的数字是右操作数,后出栈的数字是左操作数)
当前符号优先级 > 栈顶元素的优先级,符号入栈。
栈顶是左括号
当前符号无条件入栈
循环结束:
判断符号栈是否为空,如果为空,则数据栈的栈顶元素,就是最后的结果。
如果不空,一直计算,直到符号栈为空。