一、实验目的和要求
设计并实现一个整型算术表达式计算器。(链栈实现)
二、实验环境
编译器:Vscode DevC++
系统:Windows10
CPU:i5-8265U@1.60GHz
三、实验内容
1. 基于课后作业03内容,存储结构采用链式存储。基于链栈,尽量少的改动课后作业-03代码,完成计算器功能。
2. 要求抽象出链栈结构进行独立实现(建议直接利用 课堂作业-03代码)。
3. 其它要求同作业-01要求。
四、实验过程
4.1 任务定义和问题分析
使用模板类来实现链栈的入栈、出栈、判空、判满、返回栈顶元素等等
利用函数进行对运算符优先级的比较操作(需要用到迭代)
由于第3次实验报告将栈的代码写在了my_stack_first.h里面
所以此次报告 仅需将链栈写在新的类里面,并将头文件替换即可
4.2 数据结构的选择和概要设计
使用结构体创建节点
template <typename DataType>
struct node
{
DataType data;
node *next;
};
4.3 详细设计
还是使用模板类来实现链栈
template <typename DataType>
class my_stack
需要实现入栈、出栈、判空、判满、返回栈顶元素等功能
my_stack()
~my_stack()
bool IsEmpty() const
bool IsFull()
void InsertStack(const DataType x)
E_code insertstack(const DataType x)
E_code get_top(DataType &x) const
DataType GetTop()
E_code OutStack(int x = 0)
在上面一些函数有些需要注意
- 初始化函数:不需要传参 指针的性质导致 无法预定大小
- 析构函数:由于默认析构函数不能将top后继节点delete 所以需要设置特殊析构函数处理
- 判满函数:由于不能自主控制大小,所以一般不会满 直接返回假就好(存在是要加强代码的可移植性)
- 返回栈顶元素:可供两种选择 在确保无非法状态时 可直接使用 GetTop函数 如果不确定 应该使用 get_top函数 有效判断各种情况 这种情况 我认为使用switch比较好
- 出栈函数:注意到 我添加了参数 由指针的特性 增加了删除任意位置的节点 默认为0 即栈顶
需要创建计数器(count)和栈顶指针(top)
private:
int count;
node<DataType> *top;
再测试实验数据的时候发现 当算式中出现空格 会导致 空格后的字符不能读入(cin>>sh;)
所以将 读入方式改为
getline(cin, sh);
再在循环当中加入忽略空格的语句
if(sh[i]==' ')
continue;
测试 完成!!
之后想起 不能识别中文括号 所以想尝试解决一下 发现中文字符char的int型一直为-93
失败 此想法搁浅
五、测试及结果分析
5.1 实验数据
使用第三次实验的数据
5.2 结果及分析
测试表达式 | 输出结果 | 正确结果 |
1+2 | 3 | 3 |
1+2*3-6/2+2/1*0 | 4 | 4 |
12+5*(2+3)*6/2-4 | 83 | 83 |
3*0+(9-6*4/2)*(2+1) | -9 | -9 |
(1+2)+(2)+3*(4) | 17 | 17 |
-1+3*0+(9-6*4/2)*(2+1) | -10 | -10 |
(-1)*12+5*(2+3)*6/2-4 | 59 | 59 |
(-1)* 12 +5*( 2+3)* 6/2- 4 | 59 | 59 |
六、实验收获
深入理解了链栈存储结构 并进行了代码编写
认识到代码规范性对代码可移植性的影响
将类写在.h文件是个很不错的方法
七、参考文献
无
八、附录(源代码)
请自己实现链栈
cal.cpp
// #include"my_stack_first.h"
#include "my_stack_second.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
map<char, int> ys;
my_stack<char> stk_ch;
my_stack<double> stk_di;
int solve[5][5];//第一维表示待入栈运算符 第二表示栈顶运算符
//值为1 表示栈顶运算符出栈进行操作
//值为0 表示待入栈运算符入栈
//值为2 表示待入栈运算符出栈 栈顶运算符出栈 ()以及##
void init()
{
ys['+'] = 1;
ys['-'] = 1;
ys['*'] = 2;
ys['/'] = 2;
ys['('] = 3;
ys[')'] = 4;
ys['#'] = 0;
//以上是先给各个运算符编号
solve[1][0] = 0;
solve[1][1] = 1;
solve[1][2] = 1;
solve[1][3] = 0;
// solve[1][4] = 1;
//由于‘)’根本不会入栈 所以不存在4作为第二维出现
//以下注释掉的组合均是不会出现的情况
solve[2][0] = 0;
solve[2][1] = 0;
solve[2][2] = 1;
solve[2][3] = 0;
// solve[2][4] = ;
solve[3][0] = 0;
solve[3][1] = 0;
solve[3][2] = 0;
solve[3][3] = 0;
// solve[3][4] = 1;
// solve[4][0] = 1;
//不会存在这种情况
solve[4][1] = 1;
solve[4][2] = 1;
solve[4][3] = 2;
// solve[4][4] = 1;
solve[0][0] = 2;
solve[0][1] = 1;
solve[0][2] = 1;
// solve[0][3] = 0;
// solve[0][4] = 2;
}
void work(char wit)
{
char top = stk_ch.GetTop();
if (solve[ys[wit]][ys[top]] == 0)
{
stk_ch.InsertStack(wit);
return;
}
while (solve[ys[wit]][ys[top]] == 1)
{
double num2 = stk_di.GetTop();
stk_di.OutStack();
double num1 = stk_di.GetTop();
stk_di.OutStack();
switch(top){
case '+':
num1 += num2;
break;
case '-':
num1 -= num2;
break;
case '*':
num1 *= num2;
break;
case '/':
num1 /= num2;
break;
}
stk_di.InsertStack(num1);
stk_ch.OutStack();
top = stk_ch.GetTop();
}
if (solve[ys[wit]][ys[top]] == 0)
{
stk_ch.InsertStack(wit);
return;
}
if (solve[ys[wit]][ys[top]] == 2)
stk_ch.OutStack();
}
int main()
{
string sh;
getline(cin,sh);
init();
sh = '#'+sh + '#';
stk_ch.InsertStack('#');
for (int i = 1; i < sh.length();i++)
{
if(isdigit(sh[i])){
int flag = 1;
if(ys[sh[i-1]]==1&&(sh[i-2]=='('||sh[i-2]=='#'))
{
if (sh[i - 1] == '-')
flag = -1;
// cout << i << "\n";
stk_ch.OutStack();
}
int di = 0;
while (isdigit(sh[i])){
di *= 10;
di += sh[i] - '0';
i++;
}
di *= flag;
stk_di.InsertStack(di);
// cout << di;
}
if(sh[i]== ' ')
continue;
work(sh[i]);
}
// cout << "\n";
cout << stk_di.GetTop();
system("pause");
}