一、后缀表达式的计算
1、遍历后缀表达式中的数字和运算符
(1)、若当前元素为数字:进栈
(2)、当前元素为运算符:
A、从栈中弹出右操作数
B、从栈中弹出左操作数
C、根据符号进行计算
D、将运算结果压入栈中
2、遍历结束
(1)、栈中的唯一数据为运算结果
3、注意:
(1)、与数学相关的算法都需要考虑除0的情况
(2)、若是浮点数运算,避免代码中直接与0做相等比较
#ifndef QCalculatorDec_H
#define QCalculatorDec_H
#include<QQueue>
#include <QString>
#include <QStack>
class QCalculatorDec
{
protected:
QString m_exp;
QString m_result;
//分离算法
bool isDigitOrDot(QChar c);//数字和.
bool isSymbol(QChar c);//字符
bool isSign(QChar c);//符合+-
bool isOperator(QString s);//参数为Qstring 的原因是后面要将pre作为参数传入
QQueue<QString> split(const QString& exp);//将分离后的结果保存到队列中
//中缀转后缀
bool isNumber(QString s);
bool isLeft(QString s);
bool isRight(QString s);
int priority(QString s);
bool match(QQueue<QString>& exp);
bool transform(QQueue<QString>& exp, QQueue<QString>& output);
//计算结果
QString calculator(QString lp, QString op, QString rp);
QString calculator(QQueue<QString>& exp);
public:
//计算结果
bool exection(const QString& exp);
QString result();
QCalculatorDec();
~QCalculatorDec();
};
#endif // QCalculatorDec_H
QCalculatorDec.h
#ifndef _QCALCULATORUI_H_
#define _QCALCULATORUI_H_
#include <QtGui/QApplication>
#include <QLineEdit>
#include <QPushButton>
#include <QDebug>
class QCalculatorUI : public QWidget//继承自Qwid,可知。QCalculatorUI是QObject的间接子类
{
Q_OBJECT //类声明最开始处使用Q_Object关键字
QLineEdit* m_edit;//组合关系
QPushButton* m_buttons[20];
QCalculatorUI();
bool construct();
private slots://slots关键字
void onButtonClicked();//与消息的函数签名一样,消息的clicked()没有参数,所以这里也没有
public:
static QCalculatorUI* NewInstance();
void show();
~QCalculatorUI();
};
#endif // _QCALCULATORUI_H_
QCalculatorUI.h
#include "QCalculatorDec.h"
#include <QDebug>
QCalculatorDec::QCalculatorDec()
{
m_exp = "";
m_result = "";
}
//1.分离算法
bool QCalculatorDec::isDigitOrDot(QChar c)
{
return ( ('0' <= c) && (c <= '9') ) || (c == '.');
}
bool QCalculatorDec::isSymbol(QChar c)
{
return isOperator(c) || (c == '(') || (c == ')');
}
bool QCalculatorDec::isSign(QChar c)
{
return (c == '+') || (c == '-');
}
bool QCalculatorDec::isOperator(QString s)
{
return (s == "+") || (s == "-") || (s == "*") || (s == "/");
}
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;
}
//2.中缀转后缀
bool QCalculatorDec::isNumber(QString s)
{
bool ret = false;
s.toDouble(&ret);//能转换说明是数字
return ret;
}
bool QCalculatorDec::isLeft(QString s)
{
return (s == "(");
}
bool QCalculatorDec::isRight(QString s)
{
return (s == ")");
}
int QCalculatorDec::priority(QString s)
{
int ret = 0;//这里设定括号的优先级为0
if(s == "+" || s == "-")
{
ret = 1;
}
if(s == "*" || s == "/")
{
ret = 2;
}
return ret;
}
bool QCalculatorDec::match(QQueue<QString>& exp)
{
bool ret = true;
QStack<QString> statck;
for(int i=0; i<exp.length(); i++)
{
if(isLeft(exp[i]))//1.是左括号就直接入栈
{
statck.push(exp[i]);
}
else if(isRight(exp[i]))//2.由括号就判断栈顶元素是不是左括号,是就弹出不要
{
if(!statck.isEmpty() && isLeft(statck.top()))
{
statck.pop();
}
else
{
ret = false;
break;//如果有出错也就没必要往下继续判断了
}
}
}
return ret && statck.isEmpty();
}
bool QCalculatorDec::transform(QQueue<QString>& exp, QQueue<QString>& output)
{
bool ret = match(exp);
QStack<QString> statck;
output.clear();
while(ret && !exp.isEmpty())
{
QString e = exp.dequeue();
if(isNumber(e))//1.是数字直接输出
{
output.enqueue(e);
}
else if(isOperator(e))//2.是操作符先判断优先级
{
while(!statck.isEmpty() && (priority(e) <= priority(statck.top())))
{
output.enqueue(statck.pop());
}
statck.push(e);
}
else if(isLeft(e))//3.是左括号直接入栈
{
statck.push(e);
}
else if(isRight(e))//4.是右括号就把栈元素输出直至遇到左括号
{
if(!statck.isEmpty() && (!isLeft(statck.top())))
{
output.enqueue(statck.pop());
}
if(!statck.isEmpty())
{
statck.pop();
}
}
else
{
ret = false;
}
}
while (!statck.isEmpty())//5.将栈里剩余的元素全部输出
{
output.enqueue(statck.pop());
}
if(!ret)
{
output.clear();
}
return ret;
}
//计算结果
QString QCalculatorDec::calculator(QString lp, QString op, QString rp)
{
QString ret = "Error";
if(isNumber(lp) && isNumber(rp))
{
double l = lp.toDouble();
double r = rp.toDouble();
if(op == "+")
{
ret.sprintf("%f", l + r);
}
else if(op == "-")
{
ret.sprintf("%f", l - r);
}
else if(op == "*")
{
ret.sprintf("%f", l * r);
}
else if(op == "/")
{
const double p = 0.00000000000001;
if((-p < r) && (r < p))
{
ret = "Error";
}
else
{
ret.sprintf("%f", l / r);
}
}
else
{
ret = "Error";
}
}
return ret;
}
QString QCalculatorDec::calculator(QQueue<QString>& exp)
{
QString ret = "Error";
QStack<QString> statck;
while(!exp.isEmpty())
{
QString e = exp.dequeue();
if( isNumber(e) )//1.若是数字,进栈
{
statck.push(e);
}
else if( isOperator(e) )//2.是操作符,弹出右操作数,弹出左操作数,将结果入栈
{
if( !statck.isEmpty() )
{
QString rp = statck.pop();
QString lp = statck.pop();
QString result = calculator(lp, e, rp);
if(result != "Error")
{
statck.push(result);
}
else
{
break;
}
}
}
else//3.else表达式错误
{
break;
}
}
if(!statck.isEmpty() && statck.size() == 1 && isNumber(statck.top()))
{
ret = statck.pop();
}
return ret;
}
bool QCalculatorDec::exection(const QString& exp)
{
bool ret = false;
QQueue<QString> spExp = split(exp);
QQueue<QString> posExp;
m_exp = exp;
if(transform(spExp, posExp))
{
m_result = calculator(posExp);
ret = (m_result != "Error");
}
else
{
m_result = "Error";
}
return ret;
}
QString QCalculatorDec::result()
{
return m_result;
}
QCalculatorDec::~QCalculatorDec()
{
}
QCalculatorDec.cpp
#include "QCalculatorUI.h"
QCalculatorUI::QCalculatorUI() : QWidget(NULL,Qt::WindowCloseButtonHint )
{
}
bool QCalculatorUI::construct()
{
bool ret = true;
m_edit = new QLineEdit(this);//父组件是this的原因:组合关系,同生死共存亡
const char* btnText[20] =
{
"7", "8", "9", "+", "(",
"4", "5", "6", "-", ")",
"1", "2", "3", "*", "<-",
"0", ".", "=", "/", "C"
};
if(m_edit != NULL)
{
m_edit->resize(240,30);
m_edit->move(10,10);
m_edit->setReadOnly(true);//设置文本框为只读,不输入字符串
m_edit->setAlignment(Qt::AlignRight);//设置向右对齐
}
else
{
ret = false;
}
for(int i=0; (i<4) && ret; i++)//(i<4) && ret表示QLineEdit没有生成,这里也 没必要运行了
{
for(int j=0; (j<5) && ret; j++)
{
m_buttons[i*5 + j] = new QPushButton(this);
if(m_buttons[i*5 + j])
{
m_buttons[i*5 + j] ->resize(40,40);//[i*5 + j]是转换为一维来算
m_buttons[i*5 + j]->move(10 + (10 + 40)*j, 50 + (10 + 40)*i);//横坐标移五个,纵坐标移四个
m_buttons[i*5 + j]->setText(btnText[i*5 + j]);
connect(m_buttons[i*5 + j], SIGNAL(clicked()), this, SLOT(onButtonClicked()));//将信号映射到当前对象的onButtonclick()
}
else
{
ret = false;
}
}
}
return ret;
}
QCalculatorUI* QCalculatorUI::NewInstance()
{
QCalculatorUI* ret = new QCalculatorUI();
if(!(ret && ret->construct()))
{
delete ret;
ret = NULL;
}
return ret;
}
void QCalculatorUI::show()
{
QWidget::show();
setFixedSize(width(), height());//要放在show()后,否则是先固定再显示
}
void QCalculatorUI::onButtonClicked()
{
QPushButton* btn = (QPushButton*)sender();//返回一个指向发送信号的对象的指针
QString clicktext = btn->text();
if(clicktext == "<-")
{
QString text = m_edit->text();
if(text.length() > 0)
{
text.remove(text.length() - 1, 1);
m_edit->setText(text);
}
}else if(clicktext == "C")
{
m_edit->setText("");
}else if(clicktext == "=")
{
}else
{
m_edit->setText(m_edit->text() + clicktext);
}
}
QCalculatorUI::~QCalculatorUI()
{
}
QCalculatorUI.cpp
#include <QtGui/QApplication>
#include "QCalculatorUI.h"
#include "QCalculatorDec.h"
int main(int argc, char *argv[])
{
/*
QApplication a(argc, argv);
QCalculatorUI* cal = QCalculatorUI::NewInstance();
int ret =-1;
if(cal != NULL)
{
cal->show();
ret = a.exec();
delete cal;//记得删除父对象
}
return ret;
*/
QCalculatorDec c;
c.exection("-3*(2-5)+5");
qDebug() << c.result();
return 0;
}
main.cpp
二、小结
(1)、计算方法由三个不同的子算法构成
(2)、Qt项目在整体上采用面向对象分析与设计
(3)、局部的算法设计依旧使用面向过程的方法完成
(4)、Qt开发是各种开发技术的综合运用