合肥工业大学stack数据结构实验
数据结构实验报告
实验成绩:
|
姓名 |
孙源乐 |
学号 |
2020216915 |
专业班级 |
物联网20-1班 |
|
指导教师 |
张先宜 |
实验时间 |
6.1 |
实验地点 |
计算机中心楼 |
实验名称: 栈实验
- 实验目标
1) 熟练掌握栈的顺序存储结构和链式存储结构。
2) 熟练掌握栈的有关算法设计,并在顺序栈和链栈上实现。
3) 根据具体给定的需求,合理设计并实现相关结构和算法。
- 实验内容和要求
2.1.1 顺序栈的实验要求
1) 顺序栈结构和运算定义,算法的实现以库文件方式实现,比如seqStack.h,不得在测试主程序中直接实现;
2) 实验程序有较好可读性,各运算和变量的命名直观易懂,符合软件工程要求;
3) 程序有适当的注释。
2.1.2 链栈实验要求
1) 本次实验中的链栈结构指带头结点的单链表;
2) 链栈结构和运算定义,算法的实现以库文件方式实现,比如linkedStack.h,不得在测试主程序中直接实现;
3) 实验程序有较好可读性,各运算和变量的命名直观易懂,符合软件工程要求;
4) 程序有适当的注释。
2.2.1 顺序栈的实验要求
设计并实现一个顺序栈,编写算法实现下列问题的求解。
1) 利用顺序栈实现将10进制数转换为x进制数,2<=x<=36,除了阿拉伯数字字符,不够字符使用大写英文字符。要求键盘输入10进制数和转换的目标进制数。比如:37转换为20进制数为1H。
2) 对一个合法的数学表达式来说,其中的各大小括号“{”,“}”,“[”,“]”,“(”和“)”应是相互匹配的。设计算法对以字符串形式读入的表达式S,判断其中的各括号是否是匹配的。比如:“{[](){}}”是匹配的,“{[(})]”就是不匹配的。
3) 假设栈的输入序列为1、2、3、...、n,设计算法求出所有可能的出栈序列。比如输入1、2、3、4、5,可能出栈的序列为12345、13452等42个。
3.3.2 链栈实验任务
以带头结点的单链表表示链栈,编写算法实现下列问题的求解。
1) 利用链栈实现将10进制数转换为x进制数,2<=x<=36,除了阿拉伯数字字符,不够字符使用大写英文字符。要求键盘输入10进制数和转换的目标进制数。比如:37转换为20进制数为1H。
2) 对一个合法的数学表达式来说,其中的各大小括号“{”,“}”,“[”,“]”,“(”和“)”应是相互匹配的。设计算法对以字符串形式读入的表达式S,判断其中的各括号是否是匹配的。比如:“{[](){}}”是匹配的,“{[(})]”就是不匹配的。
3) 假设栈的输入序列为1、2、3、...、n,设计算法求出所有可能的出栈序列。比如输入1、2、3、4、5,可能出栈的序列为12345、13452等42个。
3.4* 栈的扩展实验
非必做内容,有兴趣的同学选做。自行选择栈的存储结构。
1) 假设栈的输入序列为1、2、3、...、n,设计算法实现对给定的一个序列,判定其是否是此栈合法的输出序列。比如输入1、2、3、4、5序列,13452为合法出栈序列;15234是不合法输出序列。
2) 利用栈求解算术表达式的值。
- 数据结构设计
- 算法设计
首先栈的顺序存储和栈的链式存储方法书上已有不在过多介绍。
值得一提的是,我采用了c++类和模板来编写stack的。便于封装函数和类型,提供了接口,便于代码的复用,节省代码量。
实验1:
算法实现如下:首先输入10进制数和要转换的进制数,然后用该十进制数除以要转换的进制数,余数入栈,更新十进制数使其为商,重复上面的求余操作直至商为0。待循环结束后,将数据栈里面的数字依次出栈,并且用switch-case语句将其转换为对应的值,然后进行输出。
实验2:
算法实现如下:1,首先定义一个char类型的栈用来装’(‘,’[’,’{’’)’,’]’,’}’等。2,表达式进行扫描。如果扫描到的字符是’(‘,’[’,’{’直接入栈,如果扫描的字符是’)’,’]’,’}’,就要取出栈顶的第一个元素和扫描到的值进行比较,如果是对称的话,就将栈顶的元素弹出。否则的话,说明该表达式的括号不匹配,结束程序。如果扫描的不是’(‘,’[’,’{’’)’,’]’,’}’,不进行任何操作,直接开启下一轮扫描。
实验3:
算法分析:首先根据题目可知便于提取出递归模型。该问题可以被拆分为俩个子问题。首先定义一个数据栈data来表示该栈便于说明情况。俩个子问题是:数据栈栈顶数据在输入队列内的数据被压入栈之前,是出栈输出,还是栈顶元素继续保留在数据栈里面,下一个数据被压入栈中,数据出队。然后递归处理下下一个数据,数据栈的入栈出栈问题。(注意分解问题一定要全面。俩个出口都有递归),递归终止条件:递归的截止条件是输入队列和数据栈都为空,此时输出输出队列内的所有元素,然后返回。注意对现场的保护,因为递归函数要传入输入输出队列和数据栈的地址,所以在每进入一次,都要对栈进行保护,要让俩个子问题的入口条件保持一致。
算法具体实现如下:
采用回溯法和递归统计所有可能的出栈序列。
情况1:当所有的入栈序列已经全部入栈后,则只能出栈
情况2:当栈为空时,只能进栈
情况3:当仍有入栈元素且栈不为空时,可以入栈,也可以出栈
入栈 -> 递归处理下一个入栈元素 -> 恢复未入栈状态
出栈 -> 将出栈元素添加到出栈序列 -> 递归处理当前入栈元素 -> 恢 复栈和出栈序列上一个的状态
递归的截止条件是输入队列和数据栈都为空,此时输出输出队列内的所有元 素,然后返回。
注意:实验3.1和实验3.2只是实现栈的存储方式不同,实现入栈出栈等操作的方式不同,但是它们都被封装成了栈类,在解决这些实验题目的算法是相通的,也就不过多介绍了。
附加题1:
首先根据题目可以发现:要想表达式输出的正确就必须要有如果一个值被先输出,那么在接下来的输出序列里面,比它小的数一定式按照递减排序的。这是栈的输出特性所决定的。
具体实现算法如下:
使用双重循环。
首先用数组来装序列的值。遍历数组,每一轮循环,都是访问一个数据,然后内部循环是从该循环的下一个值开始到数组截止,如果内循环的值小于该数据,且该数据小于栈顶的数据那么数据入栈,如果大于栈顶数据那么就说明该输出序列不合格,如果栈为空的话,直接将数据入栈。如果内循环的值大于该数据,无需执行任何指令直接进行下一轮。
附加题2:
计算表达式的值:计算方面的算法在书上有。这里简单介绍。首先要解决如何在一个字符串中判断是符号还是操作数,并且将操作数变为int。这里面用了俩个函数第一个bool isOpr(char)是判断该字符是数字,第二个char* getNum(char*,int&)将字符变成数字存在应用number里面。返回值是char*是返回遇见的数字字符里面的最后一个。然后函数cal(int,int,char)是计算。最后为了便于比较运算符的优先序列,实现函数对其进行向量化,或说是将它们对应成数字。自此前置函数完成了。
算法实现如图示:
- 运行和测试
2.1.1运行测试:
2.1.2运行测试:
2.1.3运行测试
2.2.1运行测试:
2.2.2运行测试:
2.2.3运行测试:
附加题1的运行测试:
附加题2的运行测试:
- 总结、心得和建议
实验总结:
1:以往的实验是用结构体封装数据写的,在栈的实验中我尝试了用类封装数据和函数的写法,并且通过模板,对其进行了泛化。但是美中不足的是,因为缺少对模板函数的进一步学习,所以函数模板化并没有进行成功。函数的同构来解决实验2.1和实验2.2中出现的相同的函数,只是栈的存储格式出现了一点变化。感觉使用c++中的类很方便,但是自己是初次尝试所以会出现一些bug。例如链栈的拷贝构造函数的搭建,我就写错了。
因此实验2.2的第三个问题一直出现了问题,究其原因就是我并没有给这个类中封装的数据进行申请空间,而是用传过来的一个类对象里面的数据进行重新的搭建,就是将指针重新连接了一下。所以出现了错误,这个错误我看了好久,并且在请教了同学之后才发现,也算是增长了知识了。
在实验2.2的第三个问题我还遇见了一个问题:实验2.2是核心算法是递归函数的求解(分成了俩种情况),所以要对栈和队列进行保护,保证它们在同一级的递归调用中处于相同的状态。我起初是耍了一点小聪明,把递归函数的传参设置为栈和队列而不是它们的引用或者是地址,这样队列和栈在下一层递归的改变不会影响上一层,但是想法只是方便了人,并没有方便计算机,计算机在每一次递归函数中都要拷贝队列和栈的值,对它们重新分配空间,这样导致编译器开的栈帧爆掉,使得程序运行失败。这个问题我也是找了好久才改了出来正是小聪明要不得!!
2:在编写表达式的计算中,我引入了单目运算符的计算,为了保持和双目运算符的一致性,我选择了采用先弹出俩个数据但是只对一个数据进行操作,然后未操作的数据和已经操作的数据一起压入栈中。要注意要提前压入一个无关数据避免第一个运算就是单目运算。
实验心得:
通过实验巩固和学习了栈的链式存储和顺序存储。并且通过应用题体会到了栈的优越性,并学会了用栈去解决问题。

浙公网安备 33010602011771号