计算器核心解析算法(上)

计算机如何读懂四则运算表达式?
9.3 + (3 - -0.11) * 5

后缀表达式
人类习惯的数学表达式叫做中缀表达式
另外,还有一种将运算符放在数字后面的后缀表达式
5 + 3——> 5 3 +
1 + 2 * 3 ——> 1 2 3 * +
9 + (3 - 1) *5 ——> 9 3 1 - 5* +

中缀表达式符合人类的阅读和思维习惯
后缀表达式符合计算机的运算方式
——消除了中缀表达式中的括号
——同时保留中缀表达式中的运算优先级

解决方案
1.将中缀表达式进行数字和运算符的分离
2.将中缀表达式转换为后缀表达式
3.通过后缀表达式计算最终结果

分离算法分析
所要计算的中缀表达式中包含
——数字和小数点[ 0-9或.]
——符号位[+ 或-]
——运算符[+ - * /]
——括号 [( 或 )]


9.3 + ( 3 - -0.11 ) * 5

思想:以符号作为标志对表达式中的字符逐个访问
——定义累计变量num(字符串)
——当前字符exp[i]为数字或小数点时:
    累计:num += exp[i]
——当前字符exp[i]为符号时:
   num为运算数,分离并保存
    若exp[i]为正负号
      累计符号位 +和- : num +=exp[i]
    若exp[i]为运算符
      分离并保存

for(int i=0; i<exp.length(); i++)
{
    if( exp[i]为数字或小数点)
        累计:num += exp[i];
    else if(exp[i]为符号)
    {
        if( num != "")
            分离并保存运算数: num
        if(exp[i]为正号或负号)
            符号位累计: num += exp[i]
        else
        {
            分离并保存运算符: exp[i];
        }
    }
}

难点:
——如何区分正负号与加号和减号
+ 和 - 在表达式的第一个位置    (前一个字符为空,必然是正负号)
括号后的 + 和 -                        (前一个字符是括号,必然是正负号)
运算符后的 + 和 -                     (前一个字符是运算符,必然是正负号)

QCalculatorDec.h

#ifndef _QCALCULATORDEC_H_
#define _QCALCULATORDEC_H_

#include <QString>
#include <QQueue>
#include <QStack>


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)   //判读当前的字符C究竟是不是操作符或者括号
{
    return isOperator(c) || (c == '(') || (c == ')');
}

bool QCalculatorDec::isSign(QChar c)  //判断当前的字符是不是正负号
{
    return (c == '+') || (c == '-');
}

bool QCalculatorDec::isNumber(QString s)  //判断当前的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;
    }

    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]))
        {
            if(!num.isEmpty())
            {
                ret.enqueue(num);   //如果不为空,就应该分离并保存了。保存到队列中,之后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())  //如果for循环运行结束之后,num变量里面还有没有东西呢?如果不为空,里面还保存着最后的一个运算数。应将其分离保存到返回队列中去。
    {
        ret.enqueue(num);
        qDebug() << num;
    }   //这个地方很关键,四则运算中的最后一个操作数。

    return ret;
}

main.cpp

#include <QApplication>
#include "QCalculatorUI.h"
#include "QCalculatorDec.h"

int main(int argc, char *argv[])
{
#if 0
    QApplication a(argc, argv);
    QCalculatorUI* cal = QCalculatorUI::NewInstance();
    int ret = 0;

    if(cal != NULL)
    {
        cal->show();
        ret = a.exec();
        delete cal; //当程序运行到最后时,将生成的cal对象释放掉。
    }

    return ret;
#endif

    QCalculatorDec c;

    return 0;

}

猜你喜欢

转载自www.cnblogs.com/-glb/p/12094213.html