目录
一 实验准备
1.编程语言及开发环境的选择
本实验采用c++语言qt软件开发。学习路径 最新QT从入门到实战完整版|传智教育_哔哩哔哩_bilibili
2.实现方法
中缀转后缀,后缀表达式求解
1.中缀表达式
中缀表达式是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。在中缀表达式中,运算符具有不同的优先级,并且还可以使用括号改变运算的次序,因此运算规律比较复杂,不适于计算机求解表达式。
2.后缀表达式
后缀表达式,即逆波兰式。
我们平时写的a+b是中缀表达式,写成后缀表达式就是:ab+
特点:
1)后缀表达式的操作数与中缀表达式的操作数先后次序相同,而运算符的先后次序不同;
2)后缀表达式中没有括号,而且运算符没有优先级;
3)后缀表达式计算过程严格按照从左到右的顺序进行。
3.算法思路
I 中缀表达式转后缀表达式
设置一个运算符栈,用来存放运算符。
定义一个字典,保存优先级。
从左向右依次读取算术表达式的元素X,分以下情况进行不同的处理:
(1)如果X是操作数,直接入队
(2)如果X是运算符,再分以下情况: a)如果栈为空,直接入栈。 b)如果X==”(“,直接入栈。 c)如果X==”)“,则将栈里的元素逐个出栈,并入队到后缀表达式队列中,直到第一个配对的”(”出栈。(注:“(”和“)”都不 入队) d)如果是其他操作符(+ - * /),则和栈顶元素进行比较优先级。 如果栈顶元素的优先级大于等于X,则出栈并把栈中弹出的元素入队,直到栈顶元素的优先级小于X或者栈为空。弹出完这些元素后,才将遇到的操作符压入到栈中。
(3)最后将栈中剩余的操作符全部入队。
II 后缀表达式求解
首先准备一个栈Res_Stack.
1、从左开始向右遍历后缀表达式的元素。
2、如果取到的元素是操作数,直接入栈Res_Stack,如果是运算符,从栈中弹出2个数进行运算,然后把运算结果入栈
3、当遍历完后缀表达式时,计算结果就保存在栈里了。
二 实验设计过程
1.界面设计

font: bold 14px;
padding: 6px;
background-color: rgb(30, 155, 144)21个PushButton,1个Label 和设置相应的格式
历史记录面板

//展开历史对话框
void Widget::on_Button_history_clicked()
{
if(isOpen==false){
history_dia.show();
isOpen=true;
}
else if(isOpen==true){
history_dia.close();
isOpen=false;
}
}
//将结果添加到“历史”对话框的最后并换行
history_dia.ui->textBrowser->setText
(history_dia.ui->textBrowser->document()->toPlainText()+expression+"="+QString::number(Ans)+"\n");2. 信号与槽的连接
1.信号
private slots:
void on_Button_1_clicked();
void on_Button_2_clicked();
void on_Button_3_clicked();
void on_Button_4_clicked();
void on_Button_5_clicked();
void on_Button_6_clicked();
void on_Button_8_clicked();
void on_Button_7_clicked();
void on_Button_9_clicked();
void on_Button_add_clicked();
void on_Button_0_clicked();
void on_Button_point_clicked();
void on_Button_subtract_clicked();
void on_Button_multiply_clicked();
void on_Button_divide_clicked();
void on_Button_clear_clicked();
void on_Button_back_clicked();
void on_Button_equal_clicked();
void on_Button_left_clicked();
void on_Button_right_clicked();
void on_Button_history_clicked();2.通过对槽函数的限制实现算数表达式的正确性检验
(1)当钱输入是0到9时,如果上个符号是右括号则不输入数字
void Widget::on_Button_1_clicked()
{ int i=expression.length()-1;
if(expression .length()==0){
Expression += "1";
expression += "1";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "1";
expression += "1";
ui->Screen->setText(expression);}
}
void Widget::on_Button_2_clicked()
{
int i=expression.length()-1;
if(expression .length()==0){
Expression += "2";
expression += "2";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "2";
expression += "2";
ui->Screen->setText(expression);}
}
void Widget::on_Button_3_clicked(){
int i=expression.length()-1;
if(expression .length()==0){
Expression += "3";
expression += "3";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "3";
expression += "3";
ui->Screen->setText(expression);}
}
void Widget::on_Button_4_clicked()
{
int i=expression.length()-1;
if(expression .length()==0){
Expression += "4";
expression += "4";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "4";
expression += "4";
ui->Screen->setText(expression);}
}
void Widget::on_Button_5_clicked()
{
int i=expression.length()-1;
if(expression .length()==0){
Expression += "5";
expression += "5";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "5";
expression += "5";
ui->Screen->setText(expression);}
}
void Widget::on_Button_6_clicked()
{
int i=expression.length()-1;
if(expression .length()==0){
Expression += "6";
expression += "6";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "6";
expression += "6";
ui->Screen->setText(expression);}
}
void Widget::on_Button_8_clicked(){
int i=expression.length()-1;
if(expression .length()==0){
Expression += "8";
expression += "8";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "8";
expression += "8";
ui->Screen->setText(expression);}
}
void Widget::on_Button_7_clicked()
{ int i=expression.length()-1;
if(expression .length()==0){
Expression += "7";
expression += "7";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "7";
expression += "7";
ui->Screen->setText(expression);}
}
void Widget::on_Button_9_clicked()
{
int i=expression.length()-1;
if(expression .length()==0){
Expression += "9";
expression += "9";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "9";
expression += "9";
ui->Screen->setText(expression);}
}
void Widget::on_Button_add_clicked()
{int i =expression .length() - 1;
if(expression .length()==0|| expression.at(i) == "(" ){
Expression += "0~+~";
expression += "+";
ui->Screen->setText(expression);}
else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
{
ui->Screen->setText(expression);
}
else{
Expression += "~+~";
expression += "+";
ui->Screen->setText(expression);
}
}
void Widget::on_Button_0_clicked()
{
int i=expression.length()-1;
if(expression .length()==0){
Expression += "0";
expression += "0";
ui->Screen->setText(expression);
}
else if(expression.at(i) == ")")
{
ui->Screen->setText(expression);
}
else{
Expression += "0";
expression += "0";
ui->Screen->setText(expression);}
}(2)对小数点的正确性检验,如果多个小数点则只输入一个,如果前面又括号和操作符,则不输入,如果小数点前无数字,则在小数点前补0
//如果当前按钮是 ‘.’如果前面有括号操作符小数点什么也不做
void Widget::on_Button_point_clicked()
{//如果小数点前无数字,则补0
int i =expression .length() - 1;
if(expression.length()==0||(expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/"|| expression.at(i) == "(" )){
Expression += "0.";
expression += ".";
ui->Screen->setText(expression);
}
//如果是右括号则不输入
else if(expression.at(i) == ")"||expression.at(i) == ".")
{
ui->Screen->setText(expression);
}
//如果数字中有了小数点,则不输入
else {
int falg1=0;//设置标志
int j;
//判断字符中是否有".",j为数字首字符串位置
for( j=expression .length() - 1;j>0;j--){
if(expression.at(j) == "+"|| expression.at(j) == "-" || expression.at(j) == "*" || expression.at(j) == "/"|| expression.at(j) == "(" || expression.at(j) == ")")
break;
}
//判断数字字符串是否已经有"."
for(int t=expression .length() - 1;t>j;t--)
if(expression.at(t) == "."){
falg1=1;
}
//如果有则什么也不输出
if(falg1==1){
ui->Screen->setText(expression);
}
//否则输出点
else{
Expression += ".";
expression += ".";
ui->Screen->setText(expression);
}
}
}
(3)加减乘除输入的正确性检验 ,如果前面无输入或者时左括号则补0 ,连续输入运算符,则不输入
void Widget::on_Button_add_clicked()
{int i =expression .length() - 1;
if(expression .length()==0|| expression.at(i) == "(" ){//如果前面无输入或者时左括号则补0
Expression += "0~+~";
expression += "+";
ui->Screen->setText(expression);}
//连续输入运算符,则不输入
else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
{
ui->Screen->setText(expression);
}
else{
Expression += "~+~";
expression += "+";
ui->Screen->setText(expression);
}
}void Widget::on_Button_subtract_clicked()
{int i =expression .length() - 1;
if(expression.length()==0|| expression.at(i) == "(" ){
Expression += "0~-~";
expression += "-";
ui->Screen->setText(expression);
}
else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
{
ui->Screen->setText(expression);
}
else{
Expression += "~-~";
expression += "-";
ui->Screen->setText(expression);
}
}
void Widget::on_Button_multiply_clicked()
{
int i =expression .length() - 1;
if(expression.length()==0|| expression.at(i) == "(" ){
Expression += "1~*~";
expression += "*";
ui->Screen->setText(expression);
}
else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
{
ui->Screen->setText(expression);
}
else{
Expression += "~*~";
expression += "*";
ui->Screen->setText(expression);
}
}
void Widget::on_Button_divide_clicked()
{
int i =expression .length() - 1;
if(expression.length()==0||expression.at(i) == "("){//如果前面无输入或者时左括号不输入
ui->Screen->setText(expression);
}
else if (expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
{
ui->Screen->setText(expression);
}
else{
Expression += "~/~";
expression += "/";
ui->Screen->setText(expression);
}
}(4)等号事件响应 空字符和缺少操作数不输出 补全右括号 把结果加到历史记录里,并输出算术表达式和结果
//等号按钮点击事件
void Widget::on_Button_equal_clicked()
{ //空字符输入 缺少操作数则不输入,也不输出
int i=expression.length()-1;
if (expression.length() == 0||expression.at(i) == "+"|| expression.at(i) == "-" || expression.at(i) == "*" || expression.at(i) == "/")
{
return;
}
else if(expression.length() != 0){
//补全右括号
int count1=0;
int count2=0;
for(int j=expression .length() - 1;j>=0;j--){
if(expression.at(j)=="("){
count1++;
}
else if(expression.at(j)==")"){
count2++;
}
}
if(count1>count2){
int t=count1-count2;
while(t>0){
expression += ")";
Expression += "~)~";
t--;
}
}
}
//将Expression分割,存入字符串数组ex中。ex最后一位为"#"
QStringList ex=Expression.split("~");
ex.insert(ex.length(),"#");
//计算
double Ans=this->Run(this->Transform(ex));
//将结果添加到“历史”对话框的最后并换行
history_dia.ui->textBrowser->setText
(history_dia.ui->textBrowser->document()->toPlainText()+expression+"="+QString::number(Ans)+"\n");
//将两个E/expression归零
expression.clear();
Expression.clear();
}
(5)括号限制输入,如果上一个是数字和右括号则当前左括号不输入,如果上一个是运算符,括号是,则当前右括号不输入。如果当前算数表达式中左括号的数量小于等于右括号的数量,则当前右括号不输入。
//左括号限制输入
void Widget::on_Button_left_clicked()
{
int i;
i=expression .length();
if(expression.length()==0){
expression += "(";
Expression += "~(~";
ui->Screen->setText(expression);
}
else if(expression.at(i-1) == "+"|| expression.at(i-1) == "-" || expression.at(i-1) == "*" || expression.at(i-1) == "/"||expression.at(i-1) == "(")
{
expression += "(";
Expression += "~(~";
ui->Screen->setText(expression);
}
else{
ui->Screen->setText(expression);
}
}
//右括号限制输入
void Widget::on_Button_right_clicked()
{
// int flag1=0;
int i=expression.length();
int count1=0;
int count2=0;
for(int j=expression .length() - 1;j>=0;j--){
if(expression.at(j)=="("){
count1++;
}
else if(expression.at(j)==")"){
count2++;
}
}
if(expression.length()==0){
ui->Screen->setText(expression);
}
else if(expression.at(i-1) == "+"|| expression.at(i-1) == "-" || expression.at(i-1) == "*" || expression.at(i-1) == "/"||expression.at(i-1)==")"||expression.at(i-1)=="("){
ui->Screen->setText(expression);
}
else if(count1>count2){
expression += ")";
Expression += "~)~";
ui->Screen->setText(expression);
}
}3. 算法实现
中缀表达式转后缀表达式
//中缀转换成后缀表达式
QStringList Widget::Transform(QStringList ex){
QStack<QString> stack;
stack.push("#");
QString r;
QStringList anssss;
for(int i=0;!stack.isEmpty();){
//如果ex[i]是操作数,则存入r中,直到遇到操作符为止。
if(ex[i]!="+"&&ex[i]!="-"&&ex[i]!="*"&&ex[i]!="/"&&ex[i]!="%"
&&ex[i]!="("&&ex[i]!=")"&&ex[i]!="#"){
anssss.insert(i,ex[i]);
i++;
}
//遇到了操作符时:
else {
//接下来处理操作符ex[i]
//若栈外操作符ex[i]优先级大于栈内操作符stack.top()优先级,则ex[i]进栈
if(icp(ex[i])>isp(stack.top())){
stack.push(ex[i]);
i++;
}
//若栈外操作符优先级小于栈内操作符优先级,则将栈内操作符输出到后缀表达式,并出栈。
else if(icp(ex[i])<isp(stack.top()))
{
QString x=stack.top();
anssss.insert(i,x);
stack.pop();
}
//若栈外栈内优先级相同,退栈不输出。同时,如果栈内是“(“,则读取下一字符
else if(icp(ex[i])==isp(stack.top())){
QString pop=stack.top();
stack.pop();
if(pop=="(")
i++;
}
}
}
return anssss;
}后缀表达式的计算
//取出两个操作数
bool Widget::GetOperand(double& left,double& right){
right=s.top();
s.pop();
left=s.top();
s.pop();
}
//开始计算
double Widget::Run(QStringList exx){
int i=0;double l,r;
while(i<exx.length()){
if(exx[i]!=""&&exx[i]!="+"&&exx[i]!="-"&&exx[i]!="*"&&exx[i]!="/"){
//操作数进栈
s.push(exx[i].toDouble());
i++;
}
else if(exx[i]!=""){
if(exx[i]=="+"){
this->GetOperand(l,r);
s.push(l+r);
i++;
}
else if(exx[i]=="-"){
this->GetOperand(l,r);
s.push(l-r);
i++;
}
else if(exx[i]=="*"){
this->GetOperand(l,r);
s.push(l*r);
i++;
}
else if(exx[i]=="/"){
this->GetOperand(l,r);
s.push(l/r);
i++;
}
}
else{
i++;
}
}
double ans=s.top();
s.pop();
//将“历史”对话框中的label文本改变。
history_dia.ui->label->setText("历史记录:");
ui->Screen->setText(expression+"="+QString::number(ans));
return ans;
}项目文件结构

类的定义
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QString>
#include <QStack>
#include <QDialog>
#include "history.h"
#include <QIcon>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
void paintEvent(QPaintEvent *event);
private slots:
void on_Button_1_clicked();
void on_Button_2_clicked();
void on_Button_3_clicked();
void on_Button_4_clicked();
void on_Button_5_clicked();
void on_Button_6_clicked();
void on_Button_8_clicked();
void on_Button_7_clicked();
void on_Button_9_clicked();
void on_Button_add_clicked();
void on_Button_0_clicked();
void on_Button_point_clicked();
void on_Button_subtract_clicked();
void on_Button_multiply_clicked();
void on_Button_divide_clicked();
void on_Button_clear_clicked();
void on_Button_back_clicked();
void on_Button_equal_clicked();
void on_Button_left_clicked();
void on_Button_right_clicked();
void on_Button_history_clicked();
private:
Ui::Widget *ui;
//储存两个表达式
QString expression;
QString Expression;
//建立“历史记录”对话框的对象
history history_dia;
//判断“历史记录”对话框是否打开
bool isOpen;
private:
//下面的函数可以将中缀表达式转换为后缀表达式
//运算符s位于栈外的优先级
int icp(QString s);
//运算符s位于栈内的优先级
int isp(QString s);
//将分割后的字符串作为参数,返回后缀表达式。
QStringList Transform(QStringList ex);
//实现后缀表达式的计算
private:
QStack<double> s;
//开始计算
double Run(QStringList exx);
//计算当前运算符ch
void calculate(char ch);
//从栈中取出两个操作数left和rigth
bool GetOperand(double& left,double& right);
};
#endif // WIDGET_H四 测试
简单计算器测试
五 打包发布
参考视频最新QT从入门到实战完整版|传智教育_哔哩哔哩_bilibili


打包完成。