实验目标
利用堆栈数据结构编写一个简易的计算器,实现对计算式的解析和运算。
计算式的符号包括:+、-、*、/、(、)、#,其中满足计算优先级:括号 > 乘除 > 加减,# 表示计算式结束符号。
实现思路
使用 2 个堆栈进行存储,OPTR 用于存储运算符,OPND 用于存储操作数;
程序由左至右逐个读入输入的字符,根据字符类型分别压入 OPTR 与 OPND 两个栈中。
对于运算符存储栈 OPTR ,每次压入新元素时,都会将原本栈顶元素与该新元素进行比较, 从而执行相应运算。
运算符之间的“比较”规则如下,假设有运算符 A,B:
A<B:A 优先级低于 B,压入读入的运算符,继续读取下一个字符;
A=B:A 优先级等于 B,左右括号对应,执行去括号退栈的操作,之后继续读取下一个字符;
A>B:A 优先级高于 B,弹出 1 个运算符和 2 个操作数,将它们进行运算后,得到的结果压入 OPND 中。
各算符优先级对应表:
程序一开始会自动压入 #,解析到计算式末尾的结束符 # 弹出后,结束整个计算流程。
计算式解析的流程如下:例如输入(5+4)*2#
得到结果为18 。
源代码
#define STACK_INIT_SIZE 100 //初始存储空间分配量
#define STACK_IN_CREMENT 10 //存储空间分配增量
#include <iostream>
using namespace std;
template <class T> //栈数据结构模板
struct Sqstack {
T* bottom; //栈底指针
T* top; //栈顶指针
int stacksize; //栈内存大小
};
Sqstack<char> OPTR; //运算符寄存栈
Sqstack<double> OPND; //操作数寄存栈
template <class T> //栈初始化函数模板
bool InitStack(Sqstack<T> &S)
{
S.bottom = (T *)malloc(STACK_INIT_SIZE * sizeof(T)); //分配空间
if (!S.bottom) return false; //初始化失败返回
S.top = S.bottom;
S.stacksize = STACK_INIT_SIZE;
return true;
}
template <class T> //进栈函数模板
bool Push(Sqstack<T> &S, T e)
{
if (S.top - S.bottom >= S.stacksize) {
S.bottom = (T *)realloc(S.bottom, (S.stacksize + STACK_IN_CREMENT) * sizeof(T)); //空间不足则重新分配空间
if (!S.bottom) return false; //空间分配失败
S.top = S.bottom + S.stacksize;
S.stacksize += STACK_IN_CREMENT;
}
*S.top = e;
S.top++;
return true;
}
template <class T> //出栈函数模板
bool Pop(Sqstack<T> &S, T &e)
{
if (S.top == S.bottom) return false; //空栈,出栈失败
S.top--;
e = *S.top;
return true;
}
template <class T> //获取顶部元素函数模板
T GetTop(Sqstack<T> S)
{
T e;
e = *(S.top - 1);
return e;
}
char Precede(char c1, char c2) //判断运算符优先级函数
{
if (c1 == '+' || c1 == '-') {
if (c2 == '+' || c2 == '-' || c2 == ')' || c2 == '#') return '>';
if (c2 == '*' || c2 == '/' || c2 == '(') return '<';
}
else if (c1 == '*' || c1 == '/') {
if (c2 == '+' || c2 == '-' || c2 == '*' || c2 == '/' || c2 == ')' || c2 == '#') return '>';
if (c2 == '(') return '<';
}
else if (c1 == '(') {
if (c2 == '+' || c2 == '-' || c2 == '*' || c2 == '/' || c2 == '(') return '<';
else if (c2 == ')') return '=';
//else if (c2 == '#') cout << "表达式格式有误!" << endl;
}
else if (c1 == ')') {
if (c2 == '+' || c2 == '-' || c2 == '*' || c2 == '/' || c2 == ')' || c2 == '#') return '>';
//else if (c2 == '(') cout << "表达式格式有误!" << endl;
}
else if (c1 == '#') {
if (c2 == '+' || c2 == '-' || c2 == '*' || c2 == '/' || c2 == '(') return '<';
else if (c2 == '#') return '=';
//else if (c2 == ')') cout << "表达式格式有误!" << endl;
}
}
double Operate(double x1, double x2, char c) //运算函数
{
double result;
if (c == '+') result = x1 + x2;
else if (c == '-') result = x1 - x2;
else if (c == '*') result = x1 * x2;
else if (c == '/') result = x1 / x2;
return result;
}
bool inOp(char c) //判断是否为运算符函数
{
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' || c == '#') return true;
else return false;
}
void EvaluationExpression()
{
char input; //输入的字符
InitStack<char>(OPTR); //初始化OPTR
Push<char>(OPTR, '#');
InitStack<double>(OPND); //初始化OPND
input = getchar();
while (input != '#' || GetTop<char>(OPTR) != '#') {
if (isdigit(input)) { //判断是否为数字
double t = 0;
ungetc(input, stdin); //为能实现多位数输入,将输入字符存入输入流
scanf_s("%lf", &t);
Push<double>(OPND, t); //将数字压入OPND中
input = getchar(); //继续输入
}
else if (inOp(input)) {
switch (Precede(GetTop<char>(OPTR), input)) { //操作符与栈顶元素比较
case '<':
Push<char>(OPTR, input); //压入运算符
input = getchar(); //继续输入
break;
case '=':
Pop<char>(OPTR, input); //去括号,退栈
input = getchar(); //继续输入
break;
case '>':
double x1, x2;
char Operator;
Pop<char>(OPTR, Operator); //将运算符退栈,并将运算符返回至Operator
Pop<double>(OPND, x2); //将操作数退栈,返回至x2
Pop<double>(OPND, x1); //将操作数退栈,返回至x1
Push<double>(OPND, Operate(x1, x2, Operator)); //将新运算结果压入
break;
}
}
}
cout << "运算结果:";
cout << GetTop<double>(OPND) << endl;
}
int main()
{
cout << "=========================================================" << endl;
cout << " 运算只支持加减乘除,且括号应用英文括号! " << endl;
cout << " 请在一行内完成正确的表达式,表达式最后输入#即可开始运算 " << endl;
cout << "=========================================================" << endl;
cout << "请输入表达式:";
EvaluationExpression();
return 0;
}
运行结果截图
写在最后
声明:本文内容来源于武汉理工大学2019-2020学年数据结构与算法课程实验,仅供学习参考。如有不足地方,还请指出。
代码不要无脑抄 ,建议理解思路。祝愿读者能够在编程之路上不断进步!