合肥工业大学stack数据结构实验

数据结构实验报告

                                               实验成绩:

姓名

孙源乐

学号

2020216915

专业班级

物联网20-1

指导教师

张先宜

实验时间

6.1

实验地点

计算机中心楼

 

实验名称:               栈实验                        

 

  1. 实验目标

1) 熟练掌握栈的顺序存储结构和链式存储结构。

2) 熟练掌握栈的有关算法设计,并在顺序栈和链栈上实现。

3) 根据具体给定的需求,合理设计并实现相关结构和算法。

 

  1. 实验内容和要求

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) 假设栈的输入序列为123...n,设计算法求出所有可能的出栈序列。比如输入12345,可能出栈的序列为123451345242个。

3.3.2 链栈实验任务

以带头结点的单链表表示链栈,编写算法实现下列问题的求解。

1) 利用链栈实现将10进制数转换为x进制数,2<=x<=36,除了阿拉伯数字字符,不够字符使用大写英文字符。要求键盘输入10进制数和转换的目标进制数。比如:37转换为20进制数为1H

2) 对一个合法的数学表达式来说,其中的各大小括号{”,“}”,“[”,“]”,“(”和“)”应是相互匹配的。设计算法对以字符串形式读入的表达式S,判断其中的各括号是否是匹配的。比如:“{[](){}}”是匹配的,“{[(})]”就是不匹配的。

3) 假设栈的输入序列为123...n,设计算法求出所有可能的出栈序列。比如输入12345,可能出栈的序列为123451345242个。

3.4* 栈的扩展实验

非必做内容,有兴趣的同学选做。自行选择栈的存储结构。

1) 假设栈的输入序列为123...n,设计算法实现对给定的一个序列,判定其是否是此栈合法的输出序列。比如输入12345序列,13452为合法出栈序列;15234是不合法输出序列。

2) 利用栈求解算术表达式的值。

  1. 数据结构设计

 

  1. 算法设计

首先栈的顺序存储和栈的链式存储方法书上已有不在过多介绍。

值得一提的是,我采用了c++类和模板来编写stack的。便于封装函数和类型,提供了接口,便于代码的复用,节省代码量。

实验1

算法实现如下:首先输入10进制数和要转换的进制数,然后用该十进制数除以要转换的进制数,余数入栈,更新十进制数使其为商,重复上面的求余操作直至商为0。待循环结束后,将数据栈里面的数字依次出栈,并且用switch-case语句将其转换为对应的值,然后进行输出。

实验2

算法实现如下:1,首先定义一个char类型的栈用来装(,[,{’’),],}等。2,表达式进行扫描。如果扫描到的字符是(,[,{’直接入栈,如果扫描的字符是’),],}’,就要取出栈顶的第一个元素和扫描到的值进行比较,如果是对称的话,就将栈顶的元素弹出。否则的话,说明该表达式的括号不匹配,结束程序。如果扫描的不是’(,[,{’’),],}’,不进行任何操作,直接开启下一轮扫描。

实验3

算法分析:首先根据题目可知便于提取出递归模型。该问题可以被拆分为俩个子问题。首先定义一个数据栈data来表示该栈便于说明情况。俩个子问题是:数据栈栈顶数据在输入队列内的数据被压入栈之前,是出栈输出,还是栈顶元素继续保留在数据栈里面,下一个数据被压入栈中,数据出队。然后递归处理下下一个数据,数据栈的入栈出栈问题。(注意分解问题一定要全面。俩个出口都有递归),递归终止条件:递归的截止条件是输入队列和数据栈都为空,此时输出输出队列内的所有元素,然后返回。注意对现场的保护,因为递归函数要传入输入输出队列和数据栈的地址,所以在每进入一次,都要对栈进行保护,要让俩个子问题的入口条件保持一致。

算法具体实现如下:

采用回溯法和递归统计所有可能的出栈序列。

情况1当所有的入栈序列已经全部入栈后,则只能出栈

情况2当栈为空时,只能进栈

情况3当仍有入栈元素且栈不为空时,可以入栈,也可以出栈

入栈 -> 递归处理下一个入栈元素 -> 恢复未入栈状态

出栈 -> 将出栈元素添加到出栈序列 -> 递归处理当前入栈元素 -> 复栈和出栈序列上一个的状态

递归的截止条件是输入队列和数据栈都为空,此时输出输出队列内的所有元 素,然后返回。

注意:实验3.1和实验3.2只是实现栈的存储方式不同,实现入栈出栈等操作的方式不同,但是它们都被封装成了栈类,在解决这些实验题目的算法是相通的,也就不过多介绍了。

附加题1

首先根据题目可以发现:要想表达式输出的正确就必须要有如果一个值被先输出,那么在接下来的输出序列里面,比它小的数一定式按照递减排序的。这是栈的输出特性所决定的。

具体实现算法如下:

使用双重循环。

首先用数组来装序列的值。遍历数组,每一轮循环,都是访问一个数据,然后内部循环是从该循环的下一个值开始到数组截止,如果内循环的值小于该数据,且该数据小于栈顶的数据那么数据入栈,如果大于栈顶数据那么就说明该输出序列不合格,如果栈为空的话,直接将数据入栈。如果内循环的值大于该数据,无需执行任何指令直接进行下一轮。

附加题2

计算表达式的值:计算方面的算法在书上有。这里简单介绍。首先要解决如何在一个字符串中判断是符号还是操作数,并且将操作数变为int。这里面用了俩个函数第一个bool isOprchar)是判断该字符是数字,第二个char* getNum(char*,int&)将字符变成数字存在应用number里面。返回值是char*是返回遇见的数字字符里面的最后一个。然后函数calintintchar)是计算。最后为了便于比较运算符的优先序列,实现函数对其进行向量化,或说是将它们对应成数字。自此前置函数完成了。

算法实现如图示:

 

 

 

  1. 运行和测试

2.1.1运行测试:

 

 

 

2.1.2运行测试:

 

2.1.3运行测试

 

2.2.1运行测试:

 

2.2.2运行测试:

 

2.2.3运行测试:

 

 

附加题1的运行测试:

 

附加题2的运行测试:

 

  1. 总结、心得和建议

实验总结:

1:以往的实验是用结构体封装数据写的,在栈的实验中我尝试了用类封装数据和函数的写法,并且通过模板,对其进行了泛化。但是美中不足的是,因为缺少对模板函数的进一步学习,所以函数模板化并没有进行成功。函数的同构来解决实验2.1和实验2.2中出现的相同的函数,只是栈的存储格式出现了一点变化。感觉使用c++中的类很方便,但是自己是初次尝试所以会出现一些bug。例如链栈的拷贝构造函数的搭建,我就写错了。

因此实验2.2的第三个问题一直出现了问题,究其原因就是我并没有给这个类中封装的数据进行申请空间,而是用传过来的一个类对象里面的数据进行重新的搭建,就是将指针重新连接了一下。所以出现了错误,这个错误我看了好久,并且在请教了同学之后才发现,也算是增长了知识了。

在实验2.2的第三个问题我还遇见了一个问题:实验2.2是核心算法是递归函数的求解(分成了俩种情况),所以要对栈和队列进行保护,保证它们在同一级的递归调用中处于相同的状态。我起初是耍了一点小聪明,把递归函数的传参设置为栈和队列而不是它们的引用或者是地址,这样队列和栈在下一层递归的改变不会影响上一层,但是想法只是方便了人,并没有方便计算机,计算机在每一次递归函数中都要拷贝队列和栈的值,对它们重新分配空间,这样导致编译器开的栈帧爆掉,使得程序运行失败。这个问题我也是找了好久才改了出来正是小聪明要不得!!

2:在编写表达式的计算中,我引入了单目运算符的计算,为了保持和双目运算符的一致性,我选择了采用先弹出俩个数据但是只对一个数据进行操作,然后未操作的数据和已经操作的数据一起压入栈中。要注意要提前压入一个无关数据避免第一个运算就是单目运算。

实验心得:

通过实验巩固和学习了栈的链式存储和顺序存储。并且通过应用题体会到了栈的优越性,并学会了用栈去解决问题。

 

posted @ 2022-06-02 20:13  郭楠代码  阅读(423)  评论(0)    收藏  举报