第十三课计算器核心解析算法(中)

Posted 谱写赞歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十三课计算器核心解析算法(中)相关的知识,希望对你有一定的参考价值。

一、中缀转后缀

1、中缀表达式转后缀表达式的过程类似编译过程

(1)、四则运算表达式中的括号必须匹配

(2)、根据运算符优先级进行转换

(3)、转换后的表达式中没有括号

(4)、转换后可以顺序计算出最后结果

2、转换过程

(1)、当元素e为数字:输出

(2)、当元素e为运算符

A、与栈顶运算符进行优先级比较

B、小于等于:将栈顶元素输出,转A执行

C、大于:将当前元素e入栈

(3)、当前元素为e为左括号:入栈

(4)、当前元素e为右括号:

A、弹出栈顶元素并输出,直至栈顶元素为左括号

B、将栈顶的左括号从栈中弹出不要

二、关键点:括号匹配算法

(1)、括号成对出现

(2)、左括号必须先于右括号出现

#ifndef _QCALCULATORUI_H_
#define _QCALCULATORUI_H_

#include <QtGui/QApplication>
#include <QLineEdit>
#include <QPushButton>
#include <QDebug>

class QCalculatorUI : public QWidget//继承自Qwid,可知。QCalculatorUI是QObject的间接子类
{
    Q_OBJECT    //类声明最开始处使用Q_Object关键字
    QLineEdit* m_edit;//组合关系
    QPushButton* m_buttons[20];

    QCalculatorUI();
    bool construct();

private slots://slots关键字
    void onButtonClicked();//与消息的函数签名一样,消息的clicked()没有参数,所以这里也没有

public:
    static QCalculatorUI* NewInstance();
    void show();
    ~QCalculatorUI();
};

#endif // _QCALCULATORUI_H_
QCalculatorUI.h
#include "QCalculatorUI.h"

QCalculatorUI::QCalculatorUI()  : QWidget(NULL,Qt::WindowCloseButtonHint )
{
}

bool QCalculatorUI::construct()
{

    bool ret = true;
    m_edit = new QLineEdit(this);//父组件是this的原因:组合关系,同生死共存亡
    const char* btnText[20] =
    {
        "7", "8", "9", "+", "(",
        "4", "5", "6", "-", ")",
        "1", "2", "3", "*", "<-",
        "0", ".", "=", "/", "C"
    };

    if(m_edit != NULL)
    {
        m_edit->resize(240,30);
        m_edit->move(10,10);
        m_edit->setReadOnly(true);//设置文本框为只读,不输入字符串
        m_edit->setAlignment(Qt::AlignRight);//设置向右对齐

    }
    else
    {
        ret = false;
    }

    for(int i=0; (i<4) && ret; i++)//(i<4) && ret表示QLineEdit没有生成,这里也 没必要运行了
    {
        for(int j=0; (j<5) && ret; j++)
        {
            m_buttons[i*5 + j] = new QPushButton(this);
            if(m_buttons[i*5 + j])
            {
                m_buttons[i*5 + j] ->resize(40,40);//[i*5 + j]是转换为一维来算
                m_buttons[i*5 + j]->move(10 + (10 + 40)*j, 50 + (10 + 40)*i);//横坐标移五个,纵坐标移四个
                m_buttons[i*5 + j]->setText(btnText[i*5 + j]);
                connect(m_buttons[i*5 + j], SIGNAL(clicked()), this, SLOT(onButtonClicked()));//将信号映射到当前对象的onButtonclick()
            }
            else
            {
                ret = false;
            }

        }
    }

    return ret;

}
QCalculatorUI* QCalculatorUI::NewInstance()
{
    QCalculatorUI* ret = new QCalculatorUI();

    if(!(ret && ret->construct()))
    {
        delete ret;
        ret = NULL;
    }

    return ret;
}
void QCalculatorUI::show()
{
    QWidget::show();
    setFixedSize(width(), height());//要放在show()后,否则是先固定再显示
}

void QCalculatorUI::onButtonClicked()
{
    QPushButton* btn = (QPushButton*)sender();//返回一个指向发送信号的对象的指针
    QString clicktext = btn->text();
    if(clicktext == "<-")
    {
        QString text =  m_edit->text();
        if(text.length() > 0)
        {
            text.remove(text.length() - 1, 1);
            m_edit->setText(text);
        }

    }else if(clicktext == "C")
    {
        m_edit->setText("");
    }else if(clicktext == "=")
    {

    }else
    {
        m_edit->setText(m_edit->text() + clicktext);
    }


}

QCalculatorUI::~QCalculatorUI()
{

}
QCalculatorUI.cpp
#ifndef QCalculatorDec_H
#define QCalculatorDec_H

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


class QCalculatorDec
{
protected:
    //分离算法
    bool isDigitOrDot(QChar c);//数字和.
    bool isSymbol(QChar c);//字符
    bool isSign(QChar c);//符合+-
    bool isOperator(QString s);//参数为Qstring 的原因是后面要将pre作为参数传入
    QQueue<QString> split(const QString& exp);//将分离后的结果保存到队列中

    //中缀转后缀
    bool isNumber(QString s);
    bool isLeft(QString s);
    bool isRight(QString s);
    int priority(QString s);
    bool match(QQueue<QString>& exp);
    bool tranform(QQueue<QString>& exp, QQueue<QString>& output);

public:
    QCalculatorDec();
    ~QCalculatorDec();
};

#endif // QCalculatorDec_H
QCalculatorDec.h
#include "QCalculatorDec.h"
#include <QDebug>

QCalculatorDec::QCalculatorDec()
{
    QQueue<QString> r = split("(8+3)-5");


    for(int i=0; i<r.length(); i++)
    {
        qDebug() << r[i];
    }

    QQueue<QString> output;
    tranform(r, output);

    qDebug() << endl;
    for(int i=0; i<output.length(); i++)
    {
        qDebug() << output[i];
    }

}
//1.分离算法

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::isOperator(QString s)
{
    return (s == "+") || (s == "-") || (s == "*") || (s == "/");
}

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.clear();
            }

            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;
}


//2.中缀转后缀
bool QCalculatorDec::isNumber(QString s)
{
    bool ret = false;

    s.toDouble(&ret);//能转换说明是数字

    return ret;
}
bool QCalculatorDec::isLeft(QString s)
{
    return (s == "(");
}
bool QCalculatorDec::isRight(QString s)
{
    return (s == ")");
}
int QCalculatorDec::priority(QString s)
{
    int ret = 0;//这里设定括号的优先级为0
    if(s == "+" || s == "-")
    {
        ret = 1;
    }
    if(s == "*" || s == "/")
    {
        ret = 2;
    }
    return ret;
}
bool QCalculatorDec::match(QQueue<QString>& exp)
{
    bool ret = true;
    QStack<QString> statck;

    for(int i=0; i<exp.length(); i++)
    {
        if(isLeft(exp[i]))//1.是左括号就直接入栈
        {
            statck.push(exp[i]);
        }
        else if(isRight(exp[i]))//2.由括号就判断栈顶元素是不是左括号,是就弹出不要
        {
            if(!statck.isEmpty() && isLeft(statck.top()))
            {
                statck.pop();
            }
            else
            {
                ret = false;
                break;//如果有出错也就没必要往下继续判断了
            }
        }

    }

    return ret && statck.isEmpty();
}
bool QCalculatorDec::tranform(QQueue<QString>& exp, QQueue<QString>& output)
{
    bool ret = match(exp);
    QStack<QString> statck;
    output.clear();

    while(ret && !exp.isEmpty())
    {
        QString e = exp.dequeue();
        if(isNumber(e))//1.是数字直接输出
        {
            output.enqueue(e);
        }
        else if(isOperator(e))//2.是操作符先判断优先级
        {
            while(!statck.isEmpty() && (priority(e) <= priority(statck.top())))
            {
                output.enqueue(statck.pop());
            }

            statck.push(e);

        }
        else if(isLeft(e))//3.是左括号直接入栈
        {
            statck.push(e);
        }
        else if(isRight(e))//4.是右括号就把栈元素输出直至遇到左括号
        {
            if(!statck.isEmpty() && (!isLeft(statck.top())))
            {
                output.enqueue(statck.pop());
            }
            if(!statck.isEmpty())
            {
                statck.pop();
            }

        }
        else
        {
            ret = false;
        }
    }

    while (!statck.isEmpty())//5.将栈里剩余的元素全部输出
    {
        output.enqueue(statck.pop());
    }
    if(!ret)
    {
        output.clear();
    }

    return ret;
}

QCalculatorDec::~QCalculatorDec()
{
    
}
#include <QtGui/QApplication>
#include "QCalculatorUI.h"
#include "QCalculatorDec.h"
int main(int argc, char *argv[])
{
    /*
    QApplication a(argc, argv);

    QCalculatorUI* cal = QCalculatorUI::NewInstance();
    int ret =-1;

    if(cal != NULL)
    {

        cal->show();
        ret = a.exec();
        delete cal;//记得删除父对象

    }

    return ret;
    */

    QCalculatorDec c;
    return 0;
}
main.cpp

三、小结

(1)、后缀表达式是程序计算复杂表达式的基础

(2)、中缀转后缀是基于栈数据结构的

(3)、转换过程能够发现表达式中的错误

 

以上是关于第十三课计算器核心解析算法(中)的主要内容,如果未能解决你的问题,请参考以下文章

Jsp第十三课 MVC+三层架构

wxWidgets第十三课 wxMemoryDC 使用缓存DC渲染

python第十三课——嵌套循环

linux就该这么学 第十三课

C第十三课

重学java基础第十三课:java帝国的诞生