• 第12课 计算器核心解析算法(上)


    1. 后缀表达式

    (1)人类习惯的数学表达式叫做中缀表达式

    (2)另外,还有一种将运算符放在数字后面的后缀表达式

    5 + 35 3 +
    
    1 + 2 * 31 2 3 * +
    
    9 + (31)* 59 3 15 * +

    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)四则运算表达式的计算分三个步骤

      ①数字和符号分离

      ②中缀表达式转后缀表达式

      ③根据后缀表达式计算结果

  • 相关阅读:
    Leetcode 242.有效的字母异位词 By Python
    Leetcode 344.反转字符串 By Python
    Leetcode 217.存在重复元素 By Python
    js 动态加载select触发事件
    MUI 里js动态添加数字输入框后,增加、减少按钮无效
    【 jquery 】常用
    MySql 常用语句
    CSS 选择器 知识点
    HTML 符号实体
    log4net 配置
  • 原文地址:https://www.cnblogs.com/5iedu/p/5434815.html
Copyright © 2020-2023  润新知