目录
展示效果:
在Qt中,"栈"的概念主要体现在两个层面:一是程序设计中的数据结构——栈(Stack),二是用户界面管理中的QStackedWidget
控件。下面我将分别简要介绍这两个方面:
1. 数据结构:栈
尽管Qt本身并不直接提供一个名为"Stack"的容器类,但你可以使用C++标准库中的std::stack
,或者利用数组、向量等容器配合特定的操作来模拟栈的行为。栈是一种后进先出(Last In, First Out, LIFO)的数据结构,主要操作有压栈(push)、弹栈(pop)和查看栈顶元素。
算法思路概览
本算法利用栈的先进后出特性,通过分离数字和运算符,实现复杂表达式的高效解析与计算。具体步骤如下:
-
初始化栈结构
- 数字栈:用于存储待计算的数值。
- 运算符栈:存储运算符,初始时包含一个等于号(
=
),作为终止计算的标志。
-
解析输入字符串
- 将输入的表达式视为由数字和运算符组成的序列。
- 逐字符扫描输入字符串,识别数字和运算符。
-
数字栈操作
- 遇到数字时,连续读取构成整数的所有字符,直至遇到运算符或字符串结束。
- 将形成的整数压入数字栈。
-
运算符栈操作
- 当遇到运算符时,与栈顶运算符比较优先级。
- 若栈外运算符优先级高于栈顶运算符,将其压入运算符栈。
- 若低于或等于栈顶运算符优先级,执行以下步骤:
- 弹出运算符栈顶的运算符。
- 从数字栈弹出两个数值(后弹出的为右操作数,先弹出的为左操作数)。
- 根据弹出的运算符执行相应的数学运算。
- 将计算结果重新压入数字栈。
- 重复上述步骤,直至栈外运算符被压入栈或运算符栈为空。
-
终止条件
- 当扫描至字符串末尾或遇到等于号(
=
)时,进行最终的计算,直至运算符栈清空。
- 当扫描至字符串末尾或遇到等于号(
思路图
我个人认为最主要的还是利用了栈这个先进后出的特性,可以很好的匹配这个算法的需求。
将输入的内容看为一串字符串,遍历字符串寻找自己所寻求的字符,利用C++面向对象的特性类型转变起来也更加容易
代码段:
#include "widget.h"
#include "ui_widget.h"
//按键优化
#define DEFULT_BUTTON_STYLE "\
QPushButton{\
color:#000000;\
border:1px solid #AAAAAA;\
border-radius:0;\
background-color:#FFFFFF;\
}\
QPushButton:pressed{\
color:#FFFFFF;\
background-color:#AAAAAA;\
}\
"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->setFixedSize(415,489);
this->setWindowTitle("计算器");
temp = '0';
ui->Text_2->setPlainText(temp);
ui->zerp_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->one_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->two_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->three_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->four_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->five_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->six_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->seven_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->eight_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->nine_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->sum_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->sub_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->max_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->mini_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->del_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->equal_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->C_2->setStyleSheet(DEFULT_BUTTON_STYLE);
ui->lable_2->setStyleSheet(DEFULT_BUTTON_STYLE);
}
Widget::~Widget()
{
delete ui;
}
//拆分字符
double Widget::splitNum(QString str,int &i)
{
QString temp;
double num;
while(str[i] >= '0' && str[i] <= '9')
{
temp += str[i++];
}
num = temp.toDouble();
return num;
}
//栈内优先级
int Widget::inprior(char ch)
{
int in = 0;
switch (ch)
{
case '=':
break;
case '+':
in = 3;
break;
case '-':
in = 3;
break;
case '*':
in = 5;
break;
case '/':
in = 5;
break;
default:
break;
}
return in;
}
//栈外优先级
int Widget::outprior(char str)
{
int out = 0;
switch (str)
{
case '=':
break;
case '+':
out = 2;
break;
case '-':
out = 2;
break;
case '*':
out = 4;
break;
case '/':
out = 4;
break;
default:
break;
}
return out;
}
//比较优先级
int Widget::cmpprior(int in, int out)
{
if(in > out)
{
return 1;
}
else if (in < out)
{
return -1;
}
else
{
return 0;
}
}
//计算公式
int Widget::caculator(int num1, int num2, char op)
{
switch (op)
{
case '+':
return num1 + num2;
break;
case '-':
return num2 - num1;
break;
case '*':
return num1 * num2;
break;
case '/':
return num2 / num1;
break;
default:
break;
}
}
//等于
void Widget::on_equal_2_clicked()
{
int i = 0;
int num = 0;
int num1 = 0,num2 = 0;
int result = 0;
char top,del,buf;
optr.clear();
numtr.clear();
optr.push('=');
infix = ui->Text_2->toPlainText();
if(infix.isEmpty())
return;
while(!optr.empty())
{
if(infix[i] == '0' ||infix[i] == '1' ||infix[i] == '2' ||infix[i] == '3' ||infix[i] == '4' ||infix[i] == '5' ||infix[i] == '6' ||infix[i] == '7' ||infix[i] == '8' ||infix[i] == '9')
{
num = splitNum(infix,i);
numtr.push(num);
}
else
{
top = optr.top();
switch (cmpprior(inprior(top),outprior(infix[i].toLatin1())))
{
case 1:
buf = optr.pop();
num1 = numtr.pop();
num2 = numtr.pop();
numtr.push(caculator(num1,num2,buf));
break;
case -1:
optr.push(infix[i].toLatin1());
i++;
break;
case 0:
del = optr.pop();
if(del != '=')
i++;
break;
default:
break;
}
}
result = numtr.top();
if(result == 0)
{
qDebug("运算错误");
return;
}
ui->lineEdit_2->setText(QString::number(result));
}
}
//0
void Widget::on_zerp_2_clicked()
{
infix += '0';
ui->Text_2->setPlainText(infix);
}
//1
void Widget::on_one_2_clicked()
{
infix += '1';
ui->Text_2->setPlainText(infix);
}
//2
void Widget::on_two_2_clicked()
{
infix += '2';
ui->Text_2->setPlainText(infix);
}
//3
void Widget::on_three_2_clicked()
{
infix += '3';
ui->Text_2->setPlainText(infix);
}
//4
void Widget::on_four_2_clicked()
{
infix += '4';
ui->Text_2->setPlainText(infix);
}
//5
void Widget::on_five_2_clicked()
{
infix += '5';
ui->Text_2->setPlainText(infix);
}
//6
void Widget::on_six_2_clicked()
{
infix += '6';
ui->Text_2->setPlainText(infix);
}
//7
void Widget::on_seven_2_clicked()
{
infix += '7';
ui->Text_2->setPlainText(infix);
}
//8
void Widget::on_eight_2_clicked()
{
infix += '8';
ui->Text_2->setPlainText(infix);
}
//9
void Widget::on_nine_2_clicked()
{
infix += '9';
ui->Text_2->setPlainText(infix);
}
//+
void Widget::on_sum_2_clicked()
{
infix += '+';
ui->Text_2->setPlainText(infix);
}
//-
void Widget::on_sub_2_clicked()
{
infix += '-';
ui->Text_2->setPlainText(infix);
}
//*
void Widget::on_max_2_clicked()
{
infix += '*';
ui->Text_2->setPlainText(infix);
}
//除法
void Widget::on_mini_2_clicked()
{
infix += '/';
ui->Text_2->setPlainText(infix);
}
//.
void Widget::on_lable_2_clicked()
{
infix += '.';
ui->Text_2->setPlainText(infix);
}
//归零
void Widget::on_C_2_clicked()
{
temp = '0';
infix.clear();
ui->Text_2->setPlainText(temp);
}
//删除
void Widget::on_del_2_clicked()
{
infix.remove(infix.length()-1,1);
if(infix.length() == 0)
{
temp = '0';
infix.clear();
ui->Text_2->setPlainText(temp);
return;
}
ui->Text_2->setPlainText(infix);
}
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#ifndef WIDGET_H
#define WIDGET_H
#include <QtWidgets>
#include <QStack>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
double splitNum(QString,int &i);//拆分数字
int inprior(char ch);//栈内优先级
int outprior(char ch);//栈外优先级
int cmpprior(int in,int out);//比较优先级
int caculator(int num1,int num2,char op);
private slots:
void on_zerp_2_clicked();
void on_one_2_clicked();
void on_two_2_clicked();
void on_three_2_clicked();
void on_four_2_clicked();
void on_five_2_clicked();
void on_six_2_clicked();
void on_seven_2_clicked();
void on_eight_2_clicked();
void on_nine_2_clicked();
void on_sum_2_clicked();
void on_sub_2_clicked();
void on_max_2_clicked();
void on_mini_2_clicked();
void on_lable_2_clicked();
void on_C_2_clicked();
void on_del_2_clicked();
void on_equal_2_clicked();
private:
Ui::Widget *ui;
QStack<char> optr;
QStack<double> numtr;
QString infix;
QString temp;
};
#endif // WIDGET_H