中綴與後綴表達式--代碼篇

上一篇講了原理,中綴與後綴表達式
這一片來說說代碼,要想把一段中綴表達式轉爲後綴表達式並結算處結果,需一下步驟:
1、將中綴表達式進行字符串分離:就是把操作數和操作符拎清;
2、將分離好的有序的字符串轉爲後綴表達式;
3、計算後綴表達式。

OK~上代碼:


QCalculate.h

#include <QObject>
#include <QQueue>
#include <QStack>
#include <QDebug>

class QCalculate : public QObject
{
    Q_OBJECT
public:
    explicit QCalculate(QObject *parent = nullptr);

protected:
    //是否數字或小數點
    bool isDigitalOrDot(const QChar);
    //是否運算符
    bool isOperator(const QChar);
    //是否操作數
    bool isOperand(const QString);
    //是否左括號
    bool isLeftBracket(const QString);
    //是否右括號
    bool isRightBracket(const QString);
    //結算優先級數值
    int  getPriority(const QString);

    //字符串分離
    QQueue<QString> stringSeparation(const QString str);
    //表達式轉換(中綴轉後綴)
    QQueue<QString> conversionExpression(QQueue<QString>);
    //計算後綴表達式
    QString calculate(QQueue<QString>);
    //計算兩個數的算法
    QString calculateBetweenNum(const QString,const QString,const QString);

private:
    //前綴表達式分離結果
    QQueue<QString> m_QueueResultStr;
    //後綴表達式緩存
    QQueue<QString> m_QueueExpRear;
};

QCalculate.cpp

#include "QCalculate.h"

QCalculate::QCalculate(QObject *parent) : QObject(parent)
{
    m_QueueResultStr.clear();
    m_QueueExpRear.clear();


    /************************test***************************/
    /*中綴表達式分離
     */
    QString strExp="";
    QString strInput = "-1*3.2+((-2+4)/2+6)";
    qDebug()<<"中綴表達式:"<<strInput;
    stringSeparation(strInput);
    qDebug()<<"中綴表達式分離結果:";
    for(int i=0; i<m_QueueResultStr.size(); ++i)
    {
        qDebug()<<m_QueueResultStr[i];
    }


    /*中綴表達式轉後綴表達式
     */
    strExp = "";
    conversionExpression(m_QueueResultStr);
    for(int i=0; i<m_QueueExpRear.size(); ++i)
    {
        strExp+=m_QueueExpRear[i];
    }
    qDebug()<< "後綴表達式:" << strExp;


    /*後綴表達式計算
     */
    qDebug()<< "計算結果:" << calculate(m_QueueExpRear);
    /************************test***************************/
}

bool QCalculate::isDigitalOrDot(const QChar cha)
{
    return '0' <= cha && '9' >= cha || '.' == cha;
}

bool QCalculate::isOperator(const QChar cha)
{
    return !isDigitalOrDot(cha) && !isLeftBracket(cha) && !isRightBracket(cha);
}

bool QCalculate::isOperand(const QString str)
{
    QChar chaArr[6] = {'+','-','*','/','(',')'};
    for(int i= 0; i<6; ++i)
    {
        if(chaArr[i] == str)
        {
            return false;
        }
    }
    return true;
}

bool QCalculate::isLeftBracket(const QString str)
{
    return str=='(';
}

bool QCalculate::isRightBracket(const QString str)
{
    return str==')';
}

int QCalculate::getPriority(const QString str)
{
    if('*' == str || '/' == str)
    {
        return 2;
    }
    else if('+' == str || '-' == str)
    {
        return 1;
    }
    else if('(' == str || ')' == str)
    {
        return 0;
    }
    else
    {
        return -1;
    }
}


/*************************************************
 <函數名稱>    stringSeparation
 <功    能>   字符串分離
 <參數說明>    str:輸入的中綴表達式

 <返 回 值>    分離好的字符串隊列

 <函數說明>    輸入的中綴表達式必須符合規範(可以含空格)

 <作    者>   mcq
 <時    間>   2019-11-26
 <修    改>
**************************************************/
QQueue<QString> QCalculate::stringSeparation(const QString str)
{
    //操作數緩存 (含正負數)
    QString strBuf="";

    for(int i=0; i<str.length(); ++i)
    {
        //濾掉空格
        if(str[i].isSpace())
        {
            continue;
        }
        //爲數字或小數點
        if(isDigitalOrDot(str[i]))
        {
            strBuf+= str[i];
        }
        //爲括號或符號的,包含正負號
        else
        {
            //如果操作數緩存不爲空,先入隊
            if("" != strBuf)
            {
                m_QueueResultStr.enqueue(strBuf);
                strBuf = "";
            }
            //如果爲正負號
            if( (str[i] == '+' || str[i] == '-')
                    && ( (0 == i) || (isLeftBracket(str[i-1])) || isOperator(str[i-1])) ){
                strBuf+= str[i];
            }
            //爲括號或操作符
            else{
                m_QueueResultStr.enqueue(str[i]);
            }
        }
    }

    //掃描完畢後,如果操作數緩存不爲空,則入隊
    if("" != strBuf)
    {
        m_QueueResultStr.enqueue(strBuf);
        strBuf == "";
    }

    return m_QueueResultStr;
}


/*************************************************
 <函數名稱>    conversionExpression
 <功    能>   表達式轉換(中綴轉後綴)
 <參數說明>    queTemp: 前綴表達式分離結果隊列

 <返 回 值>    轉換好的後綴表達式緩存隊列

 <函數說明>    無

 <作    者>   mcq
 <時    間>   2019-11-26
 <修    改>
**************************************************/
QQueue<QString> QCalculate::conversionExpression(QQueue<QString> queTemp)
{
    //符號棧
    QStack<QString> symbolStack;

    int iSizeQueue = queTemp.size();
    for(int i=0; i< iSizeQueue; ++i)
    {
        QString str = queTemp.dequeue();
        //如果是操作數,直接輸出
        if(isOperand(str))
        {
            m_QueueExpRear.enqueue(str);
        }
        //符號
        else
        {
            //如果是左括號,直接入棧
            if(isLeftBracket(str))
            {
                symbolStack.push(str);
            }
            //如果是右括號
            else if(isRightBracket(str))
            {
                QString cha="";
                //出棧並加入結果中,直到遇見左括號
                //利用逗號表達式,先出棧,再比較
                while( (cha=symbolStack.pop(), !isLeftBracket(cha)) )
                {
                    m_QueueExpRear.enqueue(cha);
                }
            }
            //其他操作符
            else
            {
                QString cha2="";
                bool  wasNull = false;

                if(symbolStack.isEmpty())
                {
                    symbolStack.push(str);
                    continue;
                }

                //如果當前符號優先級高於棧頂符號優先級,入棧;
                //否則,依次出棧並輸出
                while(cha2=symbolStack.pop(), getPriority(str) <= getPriority(cha2))
                {
                    m_QueueExpRear.enqueue(cha2);
                    if(symbolStack.isEmpty())
                    {
                        wasNull = true;
                        symbolStack.push(str);
                        break;
                    }
                }

                if(!wasNull)
                {
                    symbolStack.push(cha2);
                    symbolStack.push(str);
                }
            }
        }
    }

    while(!symbolStack.isEmpty())
    {
        m_QueueExpRear.enqueue(symbolStack.pop());
    }

    return m_QueueExpRear;
}


/*************************************************
 <函數名稱>    calculate
 <功    能>   後綴表達式求值
 <參數說明>    inputQueue:後綴表達式緩存隊列

 <返 回 值>    計算結果,字符串類型

 <函數說明>    無

 <作    者>   mcq
 <時    間>   2019-11-26
 <修    改>
**************************************************/
QString QCalculate::calculate(QQueue<QString> inputQueue)
{
    //操作數存放棧
    QStack<QString> stackNum;

    int iSizeMax = inputQueue.size();
    for(int i=0; i< iSizeMax; ++i)
    {
        QString strTemp = inputQueue.dequeue();
        //如果是操作數,直接入棧
        if(isOperand(strTemp))
        {
            stackNum.push(strTemp);
        }
        //如果是符號,就依次取兩個棧中元素計算,結算結果再次壓棧
        else
        {
            QString strNum1 = stackNum.pop();
            QString strNum2 = stackNum.pop();
            //這裏參數一定不能寫反,先出棧的是操作數,後出棧的纔是被操作數
            QString strRet = calculateBetweenNum(strNum2, strNum1, strTemp);
            stackNum.push(strRet);
        }
    }
    return stackNum.pop();
}


QString QCalculate::calculateBetweenNum(const QString strNum1, const QString strNum2,const QString strOperator)
{
    double iPara1 = strNum1.toDouble();
    double iPara2 = strNum2.toDouble();
    if("+" == strOperator)
    {
        return QString::number(iPara1+iPara2);
    }
    else if("-" == strOperator)
    {
        return QString::number(iPara1-iPara2);
    }
    else if("*" == strOperator)
    {
        return QString::number(iPara1*iPara2);
    }
    else if("/" == strOperator)
    {
        return QString::number(iPara1/iPara2);
    }
    else
    {
        return "";
    }
}

結果展示:
在這裏插入圖片描述


源碼下載地址:
https://download.csdn.net/download/qq_35241071/12002385

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章