一 效果展示
在开发的过程中,先实现了整数表达式求值的计算,后面再实现带括号的小数计算。分别如图1和图2所示:
图1 不带括号的整数的计算
图2 带括号的小数计算
最后还加上了除数为0的异常处理,如图3所示:
图3 除数为0,结果为INF(无穷)
二 算法
2.1 算法思路
我们一般在计算器中输入都是中缀表达式,而计算机在计算的时候,是将中缀表达式转化后缀表达式来计算结果。中缀表达式转变为后缀时,需要两个栈,分别为字符栈和数字栈,从左到右遍历中缀,遍历的每个字符和字符栈栈顶字符作比较,根据比较结果,作出处理。处理方法如图3所示:
图3 处理方法(中缀表达式转后缀表达式)
根据中缀表达式计算结果的方法,将后缀表达式从左到右依次入栈,如果数字就入栈,如果为运算符时,依次取出栈顶和栈顶的下一个元素,然后根据运算符进行运算,然后进行st[top-1] op st[top]运算,将运算结果重新入栈,持续上面的过程,直到后缀遍历完毕,栈顶就是计算结果,如图4所示:
图4 后缀表达式求值
2.2 算法代码
2.2.1 中缀转变后缀
#include <iostream>
#include <cstring>
#pragma warning(disable:4996)
using namespace std;
const int N = 1010;
char str1[N], str2[N];
float str3[N];
int tt1 = -1, tt2 = -1, tt3 = -1;
void InTo(char p, char q) { //p(top)
//压入符号栈的情况
if (tt2 == -1) { //符号栈为空 ,直接进
str2[++tt2] = q;
return;
}
if (q == '(') { //(直接进入操作符栈
str2[++tt2] = q;
return;
}
//外面的优先级高 ,直接进入操作符栈
if ((p == '+' || p == '-') && (q == '/' || q == '*')) {
str2[++tt2] = q;
return;
}
//遇到),寻找左括号,在括号之间的字符弹入操作数栈
if (q == ')') {
while (str2[tt2] != '(' && tt2 != -1) {
str1[++tt1] = str2[tt2--];
str1[++tt1] = ' ';
}
if (tt2 != -1)
tt2--;
return;
}
//里面优先级较高
else {
while ((p == '*' || p == '/') || ((p == '+' || p == '-') && (q == '+' || q == '-'))) {
if (tt2 == -1) //操作符栈为空,停止。
break;
if (str2[tt2] != '(') { //(之前的弹出,进入操作数栈
str1[++tt1] = str2[tt2--];
str1[++tt1] = ' ';
p = str2[tt2]; //更新操作符栈的栈顶
}
if (str2[tt2] == '(') //遇到(,不能再弹出
break;
}
str2[++tt2] = q;
}
}
int main(void)
{
char str[N];
int flag = 0, k = 0, t = 0, cnt = 0;
float r = 0.0, tmp = 0.0;
scanf("%s", str);
for (int i = 0; str[i] != '\0'; i++) {
while (('0' <= str[i] && str[i] <= '9') || str[i] == '.') { //数字直接进入操作数栈
str1[++tt1] = str[i++];
flag = 1;
}
if (flag) {
i--;
str1[++tt1] = ' ';
flag = 0;
}
else {
if (tt2 == -1) //非数字
InTo('0', str[i]);
else
InTo(str2[tt2], str[i]);
}
}
while (tt2 != -1) { //将结果逆序,并加上' ',变成后缀表达式。
str1[++tt1] = str2[tt2--];
str1[++tt1] = ' ';
}
printf("后缀表达式:%s\n", str1);
return 0;
}
2.2.2 后缀求值(注:应用C语言写的,没有把计算的结果变为理想状态,意味着如果结果为小数,最后保留2位小数)
for (int i = 0; i <= tt1; i++) { //后缀表示式求值
while (str1[i] == ' ')
i++;
if (i > tt1)
break;
if ('0' <= str1[i] && str1[i] <= '9') {
++tt3;
k = 1;
}
if (k) {
float res = 0.0;
while (('0' <= str1[i] && str1[i] <= '9') || str1[i] == '.') {
if (str1[i] == 46) {
t = 1;
i++;
}
if (t == 0)
str3[tt3] = str1[i++] - 48 + str3[tt3] * 10;
if (t) {
cnt++;
float temp = str1[i++] - 48;
for (int i = 0; i < cnt; i++)
temp = (temp) * 0.1;
res += temp;
}
}
str3[tt3] += res;
k = 0;
i--;
t = 0;
cnt = 0;
}
else {
if (str1[i] == '+') tmp = str3[tt3 - 1] + str3[tt3];
if (str1[i] == '-') tmp = str3[tt3 - 1] - str3[tt3];
if (str1[i] == '*') tmp = str3[tt3 - 1] * str3[tt3];
if (str1[i] == '/') tmp = str3[tt3 - 1] / str3[tt3];
tt3 -= 2;
str3[++tt3] = tmp;
for (int j = tt3 + 1; j < N; j++)
str3[j] = 0;
}
}
int Lres = int(str3[tt3]);
if(str3[tt3] - Lres < 1e-6)
printf("%d\n",Lres);
else
printf("%.2f\n", str3[tt3]);
注(该代码,中使用的变量,都是来源于2.2.1,读者可以将两段代码 放在一起观看,便于理解)
三 C++QT(UI设计)
3.1 UI设计用到C++QT中的pushbutton控件,如4*5的按键使用QT中的pushbutton控件,输入输出也用到pushbutton控件,如图
图5 UI界面
四 总结和反思
4.1 播放背景音乐
步骤:1,在pro工程文件中加入QT += multimedia(播放音乐的模块)
2,在Resources文件夹中添加要播放的音乐(格式一般为.mp3)
3,如何写代码,调用播放音乐的模块。
QMediaPlayer* music = new QMediaPlayer;
music->setMedia(QUrl("qrc:/M/lastji.mp3")); //文件地址
music->setVolume(50); //设置音量
music->play();
sleep(11000); //播放11秒(sleep函数:也要查一下,不是库函数)
music->stop();
4.2 感悟
小黑子,坚持自率,塑造更好的自己。
五 工程链接(一定要配置C++QT环境)
链接:https://pan.baidu.com/s/1bi_6K2Jdi9qhJ4i338eszQ
提取码:1017