QT 计算器练习

QT 计算器练习

一、简述

    基本实现功能:

    1、字符串加法、减法、乘法、除法(模拟笔算),幂运算(x的y次方)、阶乘运算。(实现大数的四则运算)

    2、四则运算表达式的计算

    3、组合运算(计算所有种数、输出所有组合)

    4、表达式的合法性检测:括号是否匹配、对输入进行一定的合法检测

注:没有实现小数运算、计算时会去掉小数点

二、效果

1、界面


2、加减乘除运算


3、组合、表达式、幂、阶乘运算


三、工程结构图


四、源文件

Calculator.pro文件

QT += widgets gui

HEADERS += \
    calculator.h \
    exp.h \
    getcombine.h \
    getdiv.h \
    getjiecheng.h \
    getmlt.h \
    getpow.h \
    getsub.h \
    getsum.h

SOURCES += \
    calculator.cpp \
    main.cpp \
    exp.cpp \
    getCombine.cpp \
    getDiv.cpp \
    getJieCheng.cpp \
    getMlt.cpp \
    getSub.cpp \
    getSum.cpp \
    getPow.cpp

calculator.h文件

#ifndef CALCULATOR_H
#define CALCULATOR_H

#include <QDialog>
#include <QGridLayout>
#include <QPushButton>
#include <QTextBrowser>
#include <QLabel>
#include "exp.h"
#include "getpow.h"
#include "getjiecheng.h"
#include "getcombine.h"

class Calculator : public QDialog
{
    Q_OBJECT
public:
    explicit Calculator(QWidget *parent = 0);

signals:

public slots:
    void lBtnClick();//左括号'('
    void rBtnClick();//右括号')'
    void miBtnClick();//幂'^'
    void jcBtnClick();//阶乘"n!"
    void zhBtnClick();//组合"nCm"

    void qiBtnClick();//'7'
    void baBtnClick();//'8'
    void jiuBtnClick();//'9'
    void divBtnClick();//除'/'
    void clearBtnClick();//重置resLbl,'C'

    void siBtnClick();//'4'
    void wuBtnClick();//'5'
    void liuBtnClick();//'6'
    void mltBtnClick();//乘'*'
    void delBtnClick();//退格,"DEL"

    void yiBtnClick();//'1'
    void erBtnClick();//'2'
    void sanBtnClick();//'3'
    void subBtnClick();//减'-'
    void zeroBtnClick();//'0'

    void dotBtnClick();//点'.'
    void plusBtnClick();//加'+'
    void resBtnClick();//计算结果'='
    bool IsValid(QString);//表达式合法性检测
    bool IsMatch(QString);//判断表达式是否匹配
private:
    QTextBrowser* _allResBrws;//展示表达式及所有结果
    QLabel *_resLbl;//创建一个标签,显示用户输入的表达式,计算后展示结果。
};

#endif // CALCULATOR_H

exp.h文件

#ifndef EXP_H
#define EXP_H
#include <QChar>
#include <QDebug>
#include <QVector>
#include <getmlt.h>
#include <getdiv.h>
#include <getsub.h>
#include <getsum.h>
//函数声明部分
int LeftPri(QChar op);//求左运算符op的优先级
int RightPri(QChar op);//求右运算符op的优先级
int IsOp(QChar ch);//判断ch是否是运算符
int JudgePri(QChar lop, QChar rop); //判断左右运算符的优先级
QString CountExp(QString exp);//计算表达式
void Count(QChar op);//*/+-运算
#endif // EXP_H

getcombine.h文件

#ifndef GETCOMBINE_H
#define GETCOMBINE_H
    QString GetCombine(QString str1,QString str2,QString& res);
#endif // GETCOMBINE_H

getdiv.h文件

#ifndef GETDIV_H
#define GETDIV_H
    QString GetDiv(QString,QString);
    int CmpStr(QString str1,QString str2);//比较数字字符串的大小
#endif // GETDIV_H

getjiecheng.h文件

#include <QString>
#ifndef GETJIECHENG_H
#define GETJIECHENG_H

#include "getmlt.h"
#include "getsub.h"
#include <QString>
QString GetJieCheng(QString str);
#endif // GETJIECHENG_H

getmlt.h文件

#ifndef GETMLT_H
#define GETMLT_H

#include <QString>
#include <getsub.h>
#include <stdlib.h>
    int CmpStr(QString str1,QString str2);
    QString GetMlt(QString str1,QString str2);
#endif // GETMLT_H

getpow.h文件

#ifndef GETPOW_H
#define GETPOW_H

#include <QString>
#include <getsub.h>
#include <getmlt.h>
    QString GetPow(QString,QString);
#endif // GETPOW_H

getsub.h文件

#ifndef GETSUB_H
#define GETSUB_H
#include <QString>
#include <stdlib.h>
#include <getsum.h>
    QString GetSub(QString,QString);
#endif // GETSUB_H

getsum.h文件

#ifndef GETSUM_H
#define GETSUM_H

#include <QString>
#include <stdlib.h>
    QString GetSum(QString,QString);
#endif // GETSUM_H

calculator.cpp文件

#include "calculator.h"

Calculator::Calculator(QWidget *parent) :
    QDialog(parent)
{
    if(1)
    {
    //创建一个网格布局
    QGridLayout *glay = new QGridLayout(this);
    //创建一个QTextBrowser,展示计算表达式与所有结果
    _allResBrws = new QTextBrowser;
    //设置固定高度
    _allResBrws->setFixedHeight(51);

    //创建一个标签,显示用户输入的表达式、计算结束后展示计算结果,初始文本为'0'
    _resLbl = new QLabel("0");
    //设置固定高度
    _resLbl->setFixedHeight(21);
    //设置标签样式
    _resLbl->setFrameShape(QFrame::StyledPanel);
    //设置从右向左展示文本
    _resLbl->setAlignment(Qt::AlignRight);

    //创建数字按钮以及运算符按钮
    QPushButton *lBtn = new QPushButton("(");
    QPushButton *rBtn = new QPushButton(")");
    QPushButton *miBtn = new QPushButton("^");
    QPushButton *jcBtn = new QPushButton("n!");
    QPushButton *zhBtn = new QPushButton("nCm");

    QPushButton *qiBtn = new QPushButton("7");
    QPushButton *baBtn = new QPushButton("8");
    QPushButton *jiuBtn = new QPushButton("9");
    QPushButton *divBtn = new QPushButton("/");
    QPushButton *clearBtn = new QPushButton("C");

    QPushButton *siBtn = new QPushButton("4");
    QPushButton *wuBtn = new QPushButton("5");
    QPushButton *liuBtn = new QPushButton("6");
    QPushButton *mltBtn = new QPushButton("*");
    QPushButton *delBtn = new QPushButton("DEL");

    QPushButton *yiBtn = new QPushButton("1");
    QPushButton *erBtn = new QPushButton("2");
    QPushButton *sanBtn = new QPushButton("3");
    QPushButton *subBtn = new QPushButton("-");
    QPushButton *zeroBtn = new QPushButton("0");

    QPushButton *dotBtn = new QPushButton(".");
    QPushButton *plusBtn = new QPushButton("+");
    QPushButton *resBtn = new QPushButton("=");

    //设置固定的高度
    resBtn->setFixedHeight(51);
    //将控件添加到窗体的网格布局
    glay->addWidget(_allResBrws,0,0,2,5);//将allResBrws添加到第0行第0列,占据2行,5列
    glay->addWidget(_resLbl,2,0,1,5);//将resLbl添加到第2行第0列,占据1行,5列

    glay->addWidget(lBtn,3,0,1,1);
    glay->addWidget(rBtn,3,1,1,1);
    glay->addWidget(miBtn,3,2,1,1);
    glay->addWidget(jcBtn,3,3,1,1);
    glay->addWidget(zhBtn,3,4,1,1);

    glay->addWidget(qiBtn,4,0,1,1);
    glay->addWidget(baBtn,4,1,1,1);
    glay->addWidget(jiuBtn,4,2,1,1);
    glay->addWidget(divBtn,4,3,1,1);
    glay->addWidget(clearBtn,4,4,1,1);

    glay->addWidget(siBtn,5,0,1,1);
    glay->addWidget(wuBtn,5,1,1,1);
    glay->addWidget(liuBtn,5,2,1,1);
    glay->addWidget(mltBtn,5,3,1,1);
    glay->addWidget(delBtn,5,4,1,1);

    glay->addWidget(yiBtn,6,0,1,1);
    glay->addWidget(erBtn,6,1,1,1);
    glay->addWidget(sanBtn,6,2,1,1);
    glay->addWidget(subBtn,6,3,1,1);
    glay->addWidget(zeroBtn,7,0,1,2);

    glay->addWidget(dotBtn,7,2,1,1);
    glay->addWidget(plusBtn,7,3,1,1);
    glay->addWidget(resBtn,6,4,2,1);

    //连接信号与槽函数
    connect(lBtn,SIGNAL(clicked()),this,SLOT(lBtnClick()));
    connect(rBtn,SIGNAL(clicked()),this,SLOT(rBtnClick()));
    connect(miBtn,SIGNAL(clicked()),this,SLOT(miBtnClick()));
    connect(jcBtn,SIGNAL(clicked()),this,SLOT(jcBtnClick()));
    connect(zhBtn,SIGNAL(clicked()),this,SLOT(zhBtnClick()));

    connect(qiBtn,SIGNAL(clicked()),this,SLOT(qiBtnClick()));
    connect(baBtn,SIGNAL(clicked()),this,SLOT(baBtnClick()));
    connect(jiuBtn,SIGNAL(clicked()),this,SLOT(jiuBtnClick()));
    connect(divBtn,SIGNAL(clicked()),this,SLOT(divBtnClick()));
    connect(clearBtn,SIGNAL(clicked()),this,SLOT(clearBtnClick()));

    connect(siBtn,SIGNAL(clicked()),this,SLOT(siBtnClick()));
    connect(wuBtn,SIGNAL(clicked()),this,SLOT(wuBtnClick()));
    connect(liuBtn,SIGNAL(clicked()),this,SLOT(liuBtnClick()));
    connect(mltBtn,SIGNAL(clicked()),this,SLOT(mltBtnClick()));
    connect(delBtn,SIGNAL(clicked()),this,SLOT(delBtnClick()));

    connect(yiBtn,SIGNAL(clicked()),this,SLOT(yiBtnClick()));
    connect(erBtn,SIGNAL(clicked()),this,SLOT(erBtnClick()));
    connect(sanBtn,SIGNAL(clicked()),this,SLOT(sanBtnClick()));
    connect(subBtn,SIGNAL(clicked()),this,SLOT(subBtnClick()));
    connect(zeroBtn,SIGNAL(clicked()),this,SLOT(zeroBtnClick()));

    connect(dotBtn,SIGNAL(clicked()),this,SLOT(dotBtnClick()));
    connect(plusBtn,SIGNAL(clicked()),this,SLOT(plusBtnClick()));
    connect(resBtn,SIGNAL(clicked()),this,SLOT(resBtnClick()));

    }
}


void Calculator::lBtnClick()
{
    QString text = _resLbl->text();
    QString num = ")0123456879";
    if(!num.contains(text.at(text.size()-1)))//如果最后一个字符不是")0123456879"之中的才显示,(左括号前面一个不能是数字、右括号)
    {
        if(text=="0")//如果是初始"0",将0去掉
        {
            text = "";
        }
        _resLbl->setText(text+"(");
    }

}
void Calculator::rBtnClick()
{
    QString text = _resLbl->text();
    QString op = "*/+-(.C!^";
    if(text!="0" && !op.contains(text.at(text.size()-1)))//如果不是初始"0"并且最后一个不是特殊字符才显示,(右括号前面一个不能特殊字符)
    {
        _resLbl->setText(_resLbl->text()+")");
    }
}
void Calculator::miBtnClick()
{
    QString text = _resLbl->text();
    if(text!="0" && !text.contains(QRegExp("[*/+-().C!^]")))//如果不是初始"0"并且不包含指定运算符才显示,(保证只进行一次幂运算)
    {
        _resLbl->setText(_resLbl->text()+"^");
    }
}
void Calculator::jcBtnClick()
{
    QString text = _resLbl->text();
    if(text!="0" && !text.contains(QRegExp("[*/+-().C!^]")))//如果不是初始"0"并且不包含指定运算符才显示,(保证只进行一次阶乘运算)
    {
        _resLbl->setText(_resLbl->text()+"!");
    }
}
void Calculator::zhBtnClick()
{
    QString text = _resLbl->text();
    if(text!="0" && !text.contains(QRegExp("[*/+-().C!^]")))//如果不是初始"0"并且不包含指定运算符才显示,(保证只进行一次组合运算)
    {
        _resLbl->setText(_resLbl->text()+"C");
    }
}
void Calculator::qiBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();//如果是初始"0",将0去掉
        str1 += '7';
        _resLbl->setText(str1);
    }
}
void Calculator::baBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();
        str1 += '8';
        _resLbl->setText(str1);
    }
}
void Calculator::jiuBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();
        str1 += '9';
        _resLbl->setText(str1);
    }
}
void Calculator::divBtnClick()
{
    QString text = _resLbl->text();
    QString op = "(.+-*/";
    if(text!="0" && !text.contains(QRegExp("[.C!^]")) && !op.contains(text.at(text.size()-1)))//如果不是初始"0",且不包含特殊运算符、并且最后一个不是四则运算符才显示,(两个四则运算符贴在一块表达式无效)
    {
        _resLbl->setText(_resLbl->text()+"/");
    }
}
void Calculator::clearBtnClick()
{
    _resLbl->setText("0");//置为初始"0"
}
void Calculator::siBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();
        str1 += '4';
        _resLbl->setText(str1);
    }
}
void Calculator::wuBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();
        str1 += '5';
        _resLbl->setText(str1);
    }
}
void Calculator::liuBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();
        str1 += '6';
        _resLbl->setText(str1);
    }
}
void Calculator::mltBtnClick()
{
    QString text = _resLbl->text();
    QString op = "(.+-*/";
    if(text!="0" && !text.contains(QRegExp("[.C!^]")) && !op.contains(text.at(text.size()-1)))//如果不是初始"0",且不包含特殊运算符、并且最后一个不是四则运算符才显示,(两个四则运算符贴在一块表达式无效)
    {
        _resLbl->setText(_resLbl->text()+"*");
    }
}
void Calculator::delBtnClick()
{
    QString str1 = _resLbl->text();
    if(str1!="0")//不是初始状态才进行退格
    {
        str1 = str1.remove(str1.size()-1,1);
        if(str1=="")//如果已经全部删除掉表达式,重置为初始状态"0"
        {
            _resLbl->setText("0");
        }
        else
        {
            _resLbl->setText(str1);
        }

    }
}
void Calculator::yiBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();
        str1 += '1';
        _resLbl->setText(str1);
    }
}
void Calculator::erBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();
        str1 += '2';
        _resLbl->setText(str1);
    }
}
void Calculator::sanBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();
        str1 += '3';
        _resLbl->setText(str1);
    }
}
void Calculator::subBtnClick()
{
    QString text = _resLbl->text();
    QString op = "(.+-*/";
    if(text!="0" && !text.contains(QRegExp("[.C!^]")) && !op.contains(text.at(text.size()-1)))//如果不是初始"0",且不包含特殊运算符、并且最后一个不是四则运算符才显示,(两个四则运算符贴在一块表达式无效)
    {
        _resLbl->setText(_resLbl->text()+"-");
    }
}
void Calculator::zeroBtnClick()
{
    if(_resLbl->text().right(1)!=")")//数字不能跟在右括号后面
    {
        QString str1;
        str1 = _resLbl->text()=="0"?"":_resLbl->text();
        str1 += '0';
        _resLbl->setText(str1);
    }
}
void Calculator::dotBtnClick()
{
    QString text = _resLbl->text();
    QString op = "().+-*/";
    if(text!="0" && !text.contains(QRegExp("[C!^]")) && !op.contains(text.at(text.size()-1)))//如果不是初始"0",且不包含特殊运算符、并且最后一个不是"().+-*/"之中的才显示,('.'之前只能是数字)
    {
        _resLbl->setText(_resLbl->text()+".");
    }
}
void Calculator::plusBtnClick()
{
    QString text = _resLbl->text();
    QString op = "(.+-*/";
    if(text!="0" && !text.contains(QRegExp("[.C!^]")) && !op.contains(text.at(text.size()-1)))//如果不是初始"0",且不包含特殊运算符、并且最后一个不是"(.+-*/"之中的才显示,(两个四则运算符贴在一块表达式无效)
    {
        _resLbl->setText(_resLbl->text()+"+");
    }
}
void Calculator::resBtnClick()//进行计算结果
{
    //拿到用户输入的表达式
    QString exp = _resLbl->text();
    //保存计算结果
    QString res = "";
    //进行组合运算时存储所有的组合
    QString all = "";

    if(exp.contains('^'))//表达式包含'^',进行幂运算
    {
        //保证只进行幂运算,去除其他运算符
        exp.replace(QRegExp("[*/+.C!]"),"");
        //获取底数
        QString str1 = exp.left(exp.indexOf('^')).remove('-');
        //获取指数
        QString str2 = exp.right(exp.size()-exp.indexOf('^')-1);
        //进行幂运算
        res = GetPow(str1,str2);
    }
    else if(exp.contains('!'))//表达式包含'!',进行阶乘运算
    {
        //保证只进行阶乘运算,去除其他运算符
        exp.replace(QRegExp("[*/+-.C^]"),"");
        //获取基数
        res = exp.left(exp.indexOf('!'));
        //以防表达式后面还有非法字符
        exp = res + "!";
        //进行阶乘运算
        res = GetJieCheng(res);
    }
    else if(exp.contains('C'))//表达式包含'C',进行组合运算
    {
        //保证只进行组合运算,去除其他运算符
        exp.replace(QRegExp("[*/+-.!^]"),"");
        //获取总数n
        QString str1 = exp.left(exp.indexOf('C'));
        //获取要取的个数m
        QString str2 = exp.right(exp.size()-exp.indexOf('C')-1);
        //进行组合运算
        all = "\n所有组合:\n"+GetCombine(str1,str2,res);
    }
    else//只包含四则运算
    {
        //保证只进行没有小数点的四则运算,去除'.'运算符
        exp.replace(".","");
        if(IsValid(exp))//如果计算表达式合法,才进行计算
        {
            //处理表达式、进行四则运算
            res = CountExp(exp);
        }
    }

    if(!res.isEmpty())//计算结果不为空、即输入表达式得到计算
    {
        //只显示结果
       _resLbl->setText(res);
    }
    //显示表示式与结果
    _allResBrws->setText(exp+"="+res+all);

}
bool Calculator::IsValid(QString exp)
{
    bool valid = true;
    if(IsOp(exp.at(0)))//如果表达式第一个字符是运算符,不合法
    {
        valid = false;
    }
    if(exp.at(0)=='(')//如果表达式第一个字符是运算符'(',合法
    {
        valid = true;
    }
    if(exp.contains('(') || exp.contains(')'))//如果表达式包含括号,检查括号是否匹配
    {
        valid = IsMatch(exp);
    }
    return valid;
}

bool Calculator::IsMatch(QString exp)
{
    int length = exp.size();//计算表达式的长度
    int match = true;//标志是否匹配

    //栈初始化
    QList<QChar> stack;
    int top = -1;//指示栈顶

    for(int i = 0;i<length;i++)
    {
        if(exp[i]=='(')//如果是'('进栈 (只有'('才能进栈)
        {
            ++top;
            stack.push_back(exp[i]);
        }
        else if(exp[i]==')')//如果是')'出栈
        {
            if(top == -1)//如果栈空、没有与该右括号匹配,跳出循环
            {
                match = false;
                break;
            }
            else       //如果栈不为空、与该右括号匹配、出栈(栈中只有'(')
            {
                --top;
            }

        }

    }

    if(match && top== -1)//匹配所有')',并且栈没有多于的'('
    {
        return true;
    }
    else
    {
       return false;
    }
}

exp.cpp文件

#include "exp.h"

QVector<QChar> op;//模拟栈、用来存储表达式中的运算符
int op_top = -1;//运算符索引指示

QVector<QString> num;//模拟栈、用来存储表达式中的运算数
int num_top = -1;//运算数索引指示

struct	PRI		//用来存储运算符的优先级
{
    QChar op;	//运算符
    int pri;	//优先级
};

//定义左运算符优先级结构体数组
struct PRI lpri[] = {{'=',0},{'(',1},{'+',3},{'-',3},{'*',5},{'/',5},{')',6}};

//定义右运算符优先级结构体数组
struct PRI rpri[] = {{'=',0},{'(',6},{'+',2},{'-',2},{'*',4},{'/',4},{')',1}};

int LeftPri(QChar op)//求左运算符op的优先级
{
    int i = 0;//计数器
    for(i = 0;i < sizeof(lpri)/sizeof(lpri[0]);i++)//求左运算符的个数sizeof(lpri)/siozeof(lpri[0])
    {
        if(lpri[i].op == op)//如果 左运算符结构体有匹配的运算符
        {
            return lpri[i].pri;//返回对应的运算符的优先级
        }
    }

    return -1;//没有匹配的运算符
}


int RightPri(QChar op)//求右运算符op的优先级
{
    int i = 0;//计数器
    for(i = 0;i < sizeof(rpri)/sizeof(rpri[0]);i++)//求右运算符的个数sizeof(lpri)/siozeof(lpri[0])
    {
        if(rpri[i].op == op)//如果 右运算符结构体有匹配的运算符
        {
            return rpri[i].pri;//返回对应的运算符的优先级
        }
    }

    return -1;//没有匹配的运算符
}


int IsOp(QChar ch)//判断ch是否是运算符
{
    //如果是指定的运算符则返回1,否则返回0
    if(ch == '*' || ch == '/' || ch == '+' || ch == '-' || ch == '(' || ch == ')' )
    {
        return 1;
    }
    else
    {
        return 0;
    }
}


int JudgePri(QChar lop,QChar rop)//判断左右运算符的优先级  左运算符大于右运算符返回1,相等返回0,左小于右返回-1
{
    if(LeftPri(lop)> RightPri(rop))//左运算符大于右运算符返回1
    {
        return 1;
    }
    else if(LeftPri(lop)== RightPri(rop))//相等返回0,只有左右括号这一种情况
    {
        return 0;
    }
    else                        //左运算符小于右运算符返回-1
    {
        return -1;
    }
}


QString CountExp(QString exp) //处理运算表达式
{
    //初始化,清空操作符栈、运算数栈、重置站顶指示指针
    op.clear();
    num.clear();
    op_top = num_top = -1;

    //将'='进栈,等号是为了辅助比较其他运算符
    op_top++;
    op.push_back('=');

    //临时存储一个运算数、因为表达式是字符串、需要通过运算符的位置识别出每一个运算数、
    //strnum就是临时存储识别出的运算数
    QString strnum = "";
    //表达式的指示索引,用来指示访问表达式的每一个字符
    int exp_index = 0;

    //循环扫描exp表达式,识别出每一个运算数、运算符并行操作
    while(exp_index<exp.size())
    {
        if(!IsOp(exp.at(exp_index)))//如果不是运算符,即是运算数
        {
            strnum = "";//每次识别之前需要将临时变量重置,将上次数据清除

            //遇到字符是数字,继续扫描将后面连续的数字字符组合称为一个数字字符串、存放在临时变量strnum中
            while(exp_index<exp.size() && exp.at(exp_index)>='0' && exp.at(exp_index)<='9')
            {
                strnum.insert(strnum.size(),exp.at(exp_index++));//将数字字符添加到str中,添加后i加1
            }

            //运算数进栈
            ++num_top;
            //用QVector模拟栈,出栈了并不pop,只是指示指针发生变化,
            //所以当指示索引小于QVector大小时,有空闲空间,无需申请空间
            if(num_top < num.size())
            {
                num[num_top]= strnum;
            }
            else//无空闲空间,需申请空间
            {
                num.push_back(strnum);
            }
        }
        else  //是运算符
        {
            //先进行优先级判断,然后根据优先级进行相应的操作
            switch(JudgePri(op[op_top],exp.at(exp_index)))
            {
                case -1://栈顶的运算符优先级低,进栈
                        op_top++;
                        if(op_top < op.size())
                        {
                            op[op_top]=exp.at(exp_index);
                        }
                        else
                        {
                            op.push_back(exp.at(exp_index));
                        }
                        break;
                case 0://优先级一样,说明是括号 ,只有这一种情况
                        op_top--;//将'('退栈
                        break;
                case 1://栈顶的运算符优先级高,先出栈进行计算,后入栈
                        Count(op[op_top--]);//*/+- 运算
                        if(exp.at(exp_index) != ')')//如果不是')'才入栈
                        {
                            ++op_top;
                            if(op_top < op.size())
                            {
                                op[op_top]=exp.at(exp_index);
                            }
                            else
                            {
                                op.push_back(exp.at(exp_index));
                            }
                        }
                        break;
                default:
                        break;
            }
            ++exp_index;//继续向下扫描exp
        }

    }


    for(int i = op_top;i>0;i--)//因为上面是按根据表达式执行的,扫描执行先进栈而还没有出栈的运算符
    {
        Count(op[i]);
    }
    return num[0];//num.data[0];
}



void Count(QChar op)//*/+-四则运算
{
    QString temp = "0"; //用来存放临时计算结果;
    if(op == '*')
    {
        temp = num[num_top--];//取出两个数相乘
        temp = GetMlt(temp,num[num_top--]);
        num[++num_top] = temp;//将计算结果进栈
    }
    else if(op == '/')
    {
        temp = num[num_top--];//取出被除数 注意是倒着取的
        if(temp=="0") //被除数不能为0
        {
            qDebug()<<"\n被除数为0";
            return;
        }
        temp =  GetDiv(num[num_top--],temp); //取出除数         1 ÷2 1是除数,2是被除数
        num[++num_top] = temp;//将计算结果进栈
    }
    else if(op == '+')
    {
        temp = num[num_top--];//取出两个数相加 ,顺序不影响相加
        temp = GetSum(temp,num[num_top--]);
        num[++num_top] = temp;//将计算结果进栈

    }
    else if(op == '-')
    {

        temp = num.at(num_top--);//取出被减数 ,注意是倒着取的
        temp = GetSub(num.at(num_top--),temp);
        num[++num_top] = temp;//将计算结果进栈
    }

}

getCombine.cpp文件

#include <QString>
#include <QVector>
#include "getsub.h"
#include "getsum.h"

int CmpStr(QString str1,QString str2);
QString GetCombine(QString str1,QString str2,QString& res)
{
    QVector<int> arr;  //用来存储索引集合
    int n = 0,m = 0,count = 0;//count组合种数
    n = str1.toInt();//总数
    m = str2.toInt();//取的个数
    QString all = "";//保存所有组合
    if(m>n || m<1) return "确保n>=m>=1"; //确保n>=m>=1

    for(int i=1;i<=n;i++)//填充索引
    {
        arr.push_back(i);
    }

    QVector<int> a;//用来存储每次算法产生的当前组合
    for(int i=0;i<m;i++)//第一种组合,a[0]=1,a[1]=2,...a[m-1]=m;
    {
        a.push_back(i+1);
    }

    for(int j=m;a[0]<=(n-m+1);)//当组合为最后一组时,循环结束;即a[0]=n-m+1,...,a[m-1]=n;j用来判断进位,以及进位之后的调整
    {

        for(;a[m-1]<=n;a[m-1]++)//最后一位不断递增,直到达到最大值,产生进位
        {
            for(int t=0;t<m;t++)
            {
                all.insert(all.size(),QString::number(arr[a[t]-1])+"    ");

            }
            count++;
            all.insert(all.size(),"\n");//换行,方便查看所有的组合

        }

        for(j=m-2;j>=0;j--)//判断a[1]--a[m-2]是否有进位 如果 a[m-1]>n 产生进位
        {
            a[j]++;
            if(a[j]<=(j+n-m+1))//a[j]不进位,那么a[j-1]也不进位,结束继续判断
            {
                break;
            }
        }

        for(j++;j>0 && j<m;j++)//调整,使得a[index-1],a[index],a[index]顺序排列,其中a[index]产生进位
        {
            a[j] = a[j-1]+1;
        }
    }
    //组合种数
    res.setNum(count);
    //全部组合
    return all;
}

getDiv.cpp文件

#include <QString>
#include <getdiv.h>
#include <getsub.h>
#include <stdlib.h>
#include <QDebug>

QString GetDiv(QString str1,QString str2)//模拟笔算除法
{
    int i = 0,j = 0;
    //结果:res
    QString res = "",temp = "",s1 = "";
    //计算除数长度
    int len1 = str1.length();
    //计算被除数的长度
    int len2 = str2.length();
    //指示"当前除数"的位数    "当前除数"不够除时 若是除数还有数字,则"当前除数"后面加相应的数字,否则加0
    int index = len2;

    if(len1>len2)//除数长度大于被除数,那么除数>被除数
    {
        //比如123/3  先拿到相等位数1(暂时称作“当前除数”) 若是小于被除数3则再拿一位 变成12
        s1 = str1.left(len2);
        if(CmpStr(s1,str2)<0)//若是小于被除数
        {
            s1.insert(len2,str1.at(index++));//再拿一位
        }

        for(i=0;i<len1+50;i++)//控制计算结果的位数
        {
            while(s1.size()>0 && CmpStr(s1,str2)<0)//“当前除数”小于被除数,进行补位,直到“当前除数”大于除数
            {
                res.insert(res.length(),"0");//商补0
                //若是除数还有数字,则"当前除数"后面加相应的数字,否则加0
                index>= len1?s1.insert(s1.size(),"0"):s1.insert(s1.size(),str1.at(index++));
            }

            j = 0;//j保存每次试出的商
            do
            {
                if(s1.size()>0)
                {
                    s1 = GetSub(s1,str2);//用减法试商
                    j++;//每减一次加1
                }
                else//已经减到小于0,最后一次去掉,j就是本次的商
                {
                    j = -1;
                }
            }while(s1.size()>0 && CmpStr(s1,str2) >= 0);//只要"当前除数">0 并且大于被除数 继续减法试商


            if(index>len1 || index==len1)
            {
                s1.insert(s1.size(),"0");
                while(s1.size()>0 && s1.at(0)== '0')
                {
                    s1.remove(0,1);
                }
                index++;
                if(index==len1+2 && j!=-1)
                {
                    res.insert(res.length(),".");
                }
            }
            else
            {
                s1.insert(s1.size(),str1.at(index++));
                while(s1.size()>0 && s1.at(0)== '0')
                {
                    s1.remove(0,1);
                }
            }
            if(j!=-1)res.insert(res.length(),temp.setNum(j));
        }

    }
    else //除数长度小于等于被除数,那么除数<=被除数
    {
        //保证"当前除数"大于被除数
        if(str1.size()>0 && CmpStr(str1,str2)<0)//除数<被除数
        {
            res = "0.";//结果补0,并且添加小数点
            str1.insert(len1,"0");//"当前除数"补0
        }

        //减法试商
        for(i=0;i<len2+60;i++)//试商次数,结果的位数控制
        {
            //保证"当前除数"大于被除数
            while(str1.size()>0 && CmpStr(str1,str2)<0)//除数<被除数
            {
                res.insert(res.length(),"0");//结果补0
                str1.insert(str1.length(),"0");//"当前除数"补0
            }

            //去掉"当前除数"前面的0
            while(str1.size()>0 && str1.at(0)== '0')
            {
                str1.remove(0,1);
            }

            j = 0;//每次的试商
            //循环试商
            do
            {
                if(str1.size()>0)//"当前除数"位数大于0,才进行试商(整除的时候str1为空)
                {
                    str1 = GetSub(str1,str2);//减法试商
                    j++;//每减1次,加1
                }
                else//整除的时候str1为空
                {
                    j=-1;
                }
            }while(str1.size()>0 && CmpStr(str1,str2) >= 0);//"当前除数">=被除数,继续减法试商


            str1.insert(str1.length(),"0");//试完商,"当前除数"后面补0

            while(str1.size()>0 && str1.at(0)=='0')//将"当前除数"前面的0去掉
            {
                str1.remove(0,1);
            }

            if(j!=-1)//试商不为-1,即合法
            {
                res.insert(res.length(),temp.setNum(j));//将试商追加添加到结果
            }

            if(!str1.isEmpty() && str1 != "0" && res.size() == len2)
            {
                res += ".";//不能整除时,添加小数点
            }

            if(str1.size()==0)
            {
                break;//试商结束,结束循环
            }

        }
    }
    //qDebug()<<res;
    return res;
}

int CmpStr(QString str1,QString str2)
{
    //计算两个比较数的长度
    int len1 = str1.length();
    int len2 = str2.length();

    if(len1>len2)//str1位数大
    {
        for(int i=0;i<len1-len2;i++)//补0,直到一样的位数
        {
            str2.insert(0,"0");
        }
    }
    else//str2位数>=str1
    {
        for(int i=0;i<len2-len1;i++)//补0,直到一样的位数
        {
            str1.insert(0,"0");
        }
    }

    //位数相同后,调用自带的函数进行比较
    return str1.compare(str2);
}

getJieCheng.cpp文件

#include "getjiecheng.h"

QString GetJieCheng(QString str)
{
    //0的0次方为1,1的n次方为1(n>=0)
    if(str == "0" || str == "1")
    {
        return "1";
    }
    //保存计算结果
    QString res = "1";

    while(str!="1")
    {
        //累乘一次
        res = GetMlt(res,str);
        //str减1
        str = GetSub(str,"1");
    }
    return res;
}

getMlt.cpp文件

#include <getmlt.h>

QString GetMlt(QString str1,QString str2)
{
    //获取乘数1的长度
    int len1 = str1.size();
    //获取乘数2的长度
    int len2 = str2.size();

    //申请足够的空间保存结果
    int *pres= (int *)malloc(sizeof(int)*(len1+len2));
    //将申请到的空间清零
    memset(pres,0,sizeof(int)*(len1+len2));

    //对应位相乘,并将结果存放到pres
    for(int i=0;i<len1;i++)
    {
        for(int j=0;j<len2;j++)
        {
             pres[i+j] += (str1.at(len1-1-i).digitValue())*(str2.at(len2-1-j).digitValue());

        }
    }

    //进位处理
    for(int i=0;i<len1+len2;i++)
    {
        if(pres[i]>=10)//>=10即有进位
        {
            pres[i+1] += pres[i]/10;//算出进多少个,加到高一位
            pres[i] %= 10;//取余作为本位
        }

    }

    //i指示最高非0位
    int i = len1+len2-1;
    while(pres[i]==0)
    {
        i--;
    }


    //将计算结果存放到字符串strres
    QString strres="";
    for(int j=i;j>=0;j--)
    {
        strres += QString::number(pres[j]);
    }

    //释放空间
    free(pres);
    return strres;
}

getPow.cpp文件

#include <getpow.h>

QString GetPow(QString str1,QString str2)
{
    //指数是否是负数的标志
    bool flag = false;
    //如果指数是负数
    if(str2.at(0)== '-')
    {
        flag = true;//标志指数为负数
        str2.remove(0,1);//将负号去掉,先按照正数计算
    }
    //不小于0的数的0次方,结果为1
    if(str2 == "0") return "1";
    //指数为1,基数不为0,结果为本身
    if(str2 == "1")return str1;

    //以下是指数>=2
    //指数减1,结果累积一个基数
    str2 = GetSub(str2,"1");
    //存放计算结果
    QString res = str1;

    while(str2 != "0")
    {
        //指数减1
        str2 = GetSub(str2,"1");
        //结果累积一个基数
        res = GetMlt(res,str1);
    }
    if(flag)//如果指数是负数,前面加上"1/"
    {
        res = "1/"+res;
    }
    return res;
}

getSub.cpp文件

#include <getsub.h>

QString GetSub(QString str1,QString str2)
{
    if(str1.isEmpty() || str2.isEmpty())
    {
        return "0";
    }
    //计算结果,字符串形式
    QString strres="";

    bool fushu1 = false;//指示减数是否是负数
    bool fushu2 = false;//指示被减数是否是负数

    if(str1.at(0)=='-')//减数是负数
    {
        fushu1 = true;
        str1.remove(0,1);//去掉负号
    }

    if(str2.at(0)=='-')//被减数是负数
    {
        fushu2 = true;
        str2.remove(0,1);//去掉负号
    }

    //负-负,交换str1,str2
    if(fushu1 && fushu2)
    {
        str1.swap(str2);
    }
    else if(fushu1 && !fushu2)//正-负
    {
        strres = GetSum(str1,str2);
        return strres;
    }
    else if(fushu1 && !fushu2)//负-正
    {
        strres = "-"+GetSum(str1,str2);
        return strres;
    }

    //正-正
    //减数的长度
    int len1 = str1.size();
    //被减数的长度
    int len2 = str2.size();

    //记录位数最长的
    int len = len1>len2?len1:len2;
    //申请足够空间
    int *pres= (int *)malloc(sizeof(int)*(len));
    //将申请到的空间清零
    memset(pres,0,sizeof(int)*(len));

    if(len1==len2)//减数与被减数的位数相同
    {
        if(str1.compare(str2)==0)//减数=被减数
        {
            return "0";

        }
        else if(str1.compare(str2)>0)//减数>被减数
        {

            for(int i=0;i<len1;i++)//对应位相减
            {
                 pres[i] = (str1.at(len1-1-i).digitValue())-(str2.at(len2-1-i).digitValue());
            }

        }
        else//str2>str1,被减数大于减数
        {
            //按照最小位数的、对应位相减,并存到pres
            for(int i=0;i<len1;i++)
            {
                 pres[i] = (str2.at(len2-1-i).digitValue())-(str1.at(len1-1-i).digitValue());
            }

            strres += "-";
        }
    }
    else if(len1>len2)//str1位数>str2位数
    {
        for(int i=0;i<len1-len2;i++)
        {
            str2.insert(0,"0");
        }

        for(int i=0;i<len1;i++)
        {
            pres[i] = str1.at(len1-1-i).digitValue()-str2.at(len1-1-i).digitValue();
        }


    }else//str2位数>str1位数
    {
        for(int i=0;i<len2-len1;i++)
        {
            str1.insert(0,"0");
        }
        for(int i=0;i<len2;i++)
        {
             pres[i] = (str2.at(len2-1-i).digitValue())-(str1.at(len2-1-i).digitValue());
        }
    }

    //实现借位 (处理<0的数)
    pres[len-1] -= 1;//最高位减1(注意结果倒放)
    for(int i=1;i<len-1;i++)
    {
        pres[i] += 9;//中间加9
    }
    pres[0] += 10;//最低位加10

    //借位后、进位处理  (处理>=10的数)
    for(int i=0;i<len;i++)
    {
        if(pres[i]>=10)//进位处理
        {
            pres[i+1] +=pres[i]/10;//取得多少个10,进到高一位
            pres[i]%=10;//取余数作为本位
        }

    }

    if(len==1)
    {
        pres[0] +=1;//一位数时需要加1修正
    }

    //i指示计算结果的最高非0位置
    int i = len-1;
    while(pres[i]==0)
    {
        i--;
    }

    //将结果转换成字符串
    for(int j=i;j>=0;j--)
    {
        strres += QString::number(pres[j]);
    }

    if(len1<len2)//减数小于被减数
    {
        strres.insert(0,'-');
    }
    //释放空间
    free(pres);
    return strres;
}

getSum.cpp文件

#include <getsum.h>

QString GetSum(QString str1,QString str2)
{
    //获取加数1的长度
    int len1 = str1.size();
    //获取加数2的长度
    int len2 = str2.size();

    //申请足够的空间保存计算结果
    int len = len1>len2?len1+1:len2+1;
    int *pres= (int *)malloc(sizeof(int)*len);
    //将申请到的空间清零
    memset(pres,0,sizeof(int)*(len));

    if(len1==len2)//加数1的位数与加数2的位数一样
    {
        //对应位相加
        for(int i=0;i<len1;i++)
        {
             pres[i] = (str1.at(len1-1-i).digitValue())+(str2.at(len2-1-i).digitValue());
        }

    }else if(len1 > len2)//加数1的位数>加数2的位数
    {
        //按最小位数的进行对应位相减
        for(int i=0;i<len2;i++)
        {
             pres[i] = (str1.at(len1-1-i).digitValue())+(str2.at(len2-1-i).digitValue());
        }
        //多出的直接加到结果
        for(int i= len2;i<len1;i++)
        {
            pres[i] = str1.at(len1-1-i).digitValue();
        }

    }else//加数1的位数<加数2的位数
    {
        //按最小位数的进行对应位相减
        for(int i=0;i<len1;i++)
        {
            pres[i] = (str1.at(len1-1-i).digitValue())+(str2.at(len2-1-i).digitValue());
        }
        //多出的直接加到结果
        for(int i= len1;i<len2;i++)
        {
            pres[i] = str2.at(len2-1-i).digitValue();
        }
    }

    //进位处理
    for(int i=0;i<len;i++)
    {
        if(pres[i]>=10)
        {
            pres[i+1] +=pres[i]/10;
            pres[i]%=10;
        }

    }

    //i指示最高非0位位置
    int i = len-1;
    while(pres[i]==0)
    {
        i--;
    }

    //将结果添加到结果字符串strres
    QString strres="";
    for(int j=i;j>=0;j--)
    {
        strres += QString::number(pres[j]);
    }

    //释放空间
    free(pres);
    return strres;
}

main.cpp文件

#include <QApplication>
#include <calculator.h>

int main(int argc,char* argv[])
{
    QApplication app(argc,argv);
    Calculator w;
    w.setWindowTitle("计算器");
    w.setWindowFlags(Qt::WindowCloseButtonHint);//只留下关闭按钮
    w.show();
    return app.exec();
}

五、总结

    合法性检测有待加强、实现的字符串运算的算法较为脆弱、没有实现小数运算

猜你喜欢

转载自blog.csdn.net/nanfeibuyi/article/details/80354124