QT 计算器练习(字符串运算)
一、简述
记-计算器练习。字符串的"加减乘除"操作。
例子打包:链接: https://pan.baidu.com/s/1BjP-tmu5bafJv_ibxlXObg 提取码: k1m6
基本实现功能:
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();
}
五、总结
合法性检测有待加强、实现的字符串运算的算法较为脆弱、没有实现小数运算