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(); }
五、总结
合法性检测有待加强、实现的字符串运算的算法较为脆弱、没有实现小数运算