1. 后缀表达式
(1)人类习惯的数学表达式叫做中缀表达式
(2)另外,还有一种将运算符放在数字后面的后缀表达式
5 + 3 → 5 3 + 1 + 2 * 3 → 1 2 3 * + 9 + (3 – 1)* 5 → 9 3 1 – 5 * +
2. 中缀 or 后缀
(1)中缀表达式符合人类的阅读和思维习惯
(2)后缀表达式符合计算机的运算方式
①消除了中缀表达式中的括号
②同时保留中缀表达式中的运算优先级
3. 计算器核心算法
(1)解决方案
①将中缀表达式进行数字和运算符的分离
②将中缀表达式转换为后缀表达式
③通过后缀表达式计算最终结果
4. 分离算法分析
(1)中缀表达式(如:9.3 + ( 3 - - 0.11 ) * 5)包含:
①数字和小数点:0-9或.
②符号位:+或-
③运算符:+、-、*、/
④括号:(或)
(2)思想:以符号作为标志对表达式中的字符逐个访问
①定义累计变量num:存储当前读入的连续数字组成一个串
②当前字符exp[i]为数字或小数点时:num += exp[i];//累计
③当前字符exp[i]为符号时:
A.num为运算数,分离并保存运算数num
B.若exp[i]为正负号时: num +=exp[i];//累计符号位+和-,即num中加入符号位
C.若exp[i]为运算符时:分离并保存运算符(含左右括号)
(3)伪代码
(4)难点:如何区分正负号与作为运算符的加号和减号
①+和-在表达式的第一个位置,则表示正负号
②括号后的+和-,也表示正负号
③运算符后的+或-,表示正负号
+9.3 + ( -3 - - 0.11 ) * -5
【编程实验】表达式分离算法
//QCalculatorDec.h
#ifndef QCALCULATORDEC_H #define QCALCULATORDEC_H #include <QString> #include <QStack> #include <QQueue> class QCalculatorDec { protected: QString m_exp; QString m_result; bool isDigitOrDot(QChar c); bool isSymbol(QChar c); //操作符或左右括号 bool isSign(QChar c); //符号位+或- bool isNumber(QString s); bool isOperator(QString s); bool isLeft(QString s); bool isRight(QString s); int priority(QString s); QQueue<QString> split(const QString& exp); public: QCalculatorDec(); ~QCalculatorDec(); bool expression(const QString& exp); QString expression(); QString result(); }; #endif // QCALCULATORDEC_H
//QCalculatorDec.cpp
#include "QCalculatordec.h" #include <QDebug> QCalculatorDec::QCalculatorDec() { m_exp = ""; m_result = ""; QQueue<QString> r = split("+9.11 + (-3 - -1) * -5"); for(int i = 0;i < r.length(); i++) { qDebug() << r[i]; } } QCalculatorDec::~QCalculatorDec() { } 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::isNumber(QString s) { bool ret = false; s.toDouble(&ret); //将字符串转为数字 return ret; } bool QCalculatorDec::isOperator(QString s) { return (s == "+") || (s == "-") ||(s == "*") ||(s == "/"); } bool QCalculatorDec::isLeft(QString s) { return (s == "("); } bool QCalculatorDec::isRight(QString s) { return (s == ")"); } int QCalculatorDec::priority(QString s) { int ret = 0; if((s == "+") || (s =="-")) { ret = 1; }else if((s == "*") || (s == "/")) { ret = 2; } return ret; } bool QCalculatorDec::expression(const QString &exp) { bool ret =false; return ret; } QString QCalculatorDec::result() { return m_result; } 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])){ //遇标识符时,表示读到的己经不是数字了,就将num分离并保存起来 if(!num.isEmpty()) { ret.enqueue(num);//num进队列,保存起来 num.clear(); } //如果当前这个非数字的标识符是+或-,则进一步判断是正负号,还是运算符 //当+或-的前一个有效字符为空、左括号或运算符时,这时他们表示正负号。如+9、(-3、5- -3 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; }
5. 小结
(1)QString中的每个字符为QChar
(2)Qt中提供了开发中不可或缺的数据结构类
(3)四则运算表达式的计算分三个步骤
①数字和符号分离
②中缀表达式转后缀表达式
③根据后缀表达式计算结果