zoukankan      html  css  js  c++  java
  • 计算器核心解析算法(上)

    计算机如何读懂四则运算表达式?
    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;
    
    }
  • 相关阅读:
    2018.12.30【NOIP提高组】模拟赛C组总结
    【NOIP2007提高组】矩阵取数游戏
    【NOIP2007提高组】字符串的展开
    【NOIP2007提高组】统计数字
    2018.12.22【NOIP提高组】模拟B组总结
    【NOIP2013模拟11.5A组】cza的蛋糕(cake)
    CDQ分治总结
    O(2),O(3),Ofast 手动开[吸氧]
    【NOIP2013模拟11.6A组】灵能矩阵(pylon)
    【GDKOI2012模拟02.01】数字
  • 原文地址:https://www.cnblogs.com/-glb/p/12094213.html
Copyright © 2011-2022 走看看