数据结构实验指导书Word格式文档下载.docx
《数据结构实验指导书Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《数据结构实验指导书Word格式文档下载.docx(30页珍藏版)》请在冰豆网上搜索。
子程序(或过程、函数)包含的程序行数太多,易于造成理解的困难。
控制循环和判断等语句的连续嵌套的深度。
程序的目的性必须明确。
对每一段程序完成的作用,除非常明显的除外,尽可能加以注释。
这会对程序的调试提供很多方便。
另外,根据情况可以设立若干调试点,即输出若干信息,用于验证和你的设想是否一致。
3、上机调试程序
自底向上,先调试底层模块,再调试上层模块。
最后,整个程序进行联调。
调试正确后将源程序和运行结果加以输出。
4、实验报告的书写
(1)需求分析
问题描述,求解的问题是什么。
包括实验的任务、输入、输出、功能、测试数据等。
(2)概要设计
设计思想:
存储结构、主要的算法思想。
设计表示:
主程序、子程序(过程或函数)的规格说明,通过调用关系图表示它们之间的调用关系。
(3)详细设计
数据类型。
主程序和其他模块的算法或算法框架。
(4)调试分析
问题是如何解决的,讨论与分析、改进设想、经验与体会、时空复杂度等。
至少写三点。
(5)测试结果
列出你的测试结果,包括输入的测试数据和输出的结果。
测试数据应该完整和严格,必要时用多组数据进行测试。
(6)用户手册:
使用说明。
即说明你的程序在什么环境下运行,怎么运行等。
(7)附录
源程序文件名,实验结束时源程序的电子稿要归档。
数据结构与算法实验时间安排(32学时)
实验
内容
学时数
起止周
实验一
大整数相加
16
1—8
实验二
栈序列匹配
8
9—12
实验三
二叉排序树
13—16
实验四
最小生成树
数据结构与算法实验时间安排(16学时)
8
4
数据结构实验报告示例
约瑟夫环
一、需求分析
1、实验任务是用循环单链表(不带头结点)来实现约瑟夫环。
循环单链表的结点结构中包含环内代表人的编号和密码。
2、对于输入的人数(n)和n个密码,建立不带头结点的单循环链表。
3、对于密码m,从相对的第一个人开始报到第m个人,输出相对于开始报数的第m个人的信息。
4、输出过程及输出完n个人的信息,即实现了约瑟夫环的功能。
5、测试数据
m的初值设为6;
(1)对于n=7,7个人的密码依次为:
3,1,7,2,4,8,4进行测试。
(2)对于从键盘输入的n和n个人的密码进行测试。
二、概要设计
1、数据类型
(1)n个人的编号和密码的数据元素结构
typedefstruct//用于接收数据的输入
{intnum;
intm;
}data;
(2)单向循环链表结点结构
typedefstructnode
{intnum;
node*next;
}node,*link;
2、算法思想
(1)输入n个人的密码,分别和依次按1到n的编号,输入到一个结构体数组,以便为建立单循环链表作数据准备;
(2)根据结构体数组中的数据,建立单循环链表;
(3)由得到的单向循环链表,根据约瑟夫问题的要求,构造约瑟夫函数,该函数中设置2个指针p和q,p指向当前报数的结点,q指向p结点后面的结点,开始时,q应指向单向循环链表的最后一个结点。
对于出列的人(结点),在该函数中输出其编号。
该函数被主函数调用。
(4)在主函数中设置结构体数组,调用输入模块,把输入的n个人的密码和依次按1到n的编号,存储到一个结构体数组,然后调用建立有n个结点构成的单向循环链表的函数,最后调用约瑟夫函数,实现约瑟夫问题的求解。
3、各子模块
(1)输入数据模块
该模块中输入n及n个人的编号和密码,依次存储于data类型的结构体数组;
(2)建立单循环链表模块
该模块中根据结构数组中的数据,建立不带头结点的单循环链表,其结点中的数据是人的编号和密码;
(3)约瑟夫问题求解模块
该模块中根据单向循环链表,从第一个人(结点)开始报数,报到密码m时(初始密码m可为6)该(人)结点出列,并输出相应的信息和得到新的密码,为下一次报数做准备,直至每个人(结点)全部出列,输出的信息即为约瑟夫问题的求解。
4、主模块及与子模块的调用关系
(1)主模块
设置data类型的结构体数组和有关变量,然后依次调用输入数据模块、建立单循环链表模块和约瑟夫问题求解模块。
(2)各模块之间的调用关系
主程序模块
输入数据模块建立单循环链表模块约瑟夫问题求解模块
三、详细设计
1、数据结构
typedefstruct
typedefstructnode
structnode*next;
2、输入数据模块(用源代码也可以,但以伪代码比较好,下同)
voidinputdata(intn,dataman[])
{
输入n;
fori=0ton-1
输入密码m;
mani.num←i+1;
mani.d←m;
}
}
3、建立单循环链表模块
voidcreatelinklist(intn,dataman[],link&
l)
{
linkl,p,q;
l←newnode;
l->
num=←man0.num;
l->
m←man0.m;
q=l;
fori=1ton-1
{
p=←newnode;
p->
num=←mani.num;
p->
m←mani.m;
q->
next←p;
q←p;
}
next←l;
4、约瑟夫问题求解模块
voidjoseph(linkl,intn)
linkq,p,s;
m=6;
q←l->
next;
while(q->
next≠l)q←q->
p←l;
fori=0ton-1//重复n次
forj=1tom-1//找第m个人
{
p←p->
s←p;
next←p->
outputs->
num;
m←s->
m;
deletes;
5、主程序模块
voidmain()
linkl;
intn;
dataman[100];
inputn;
inputdata(n,man);
createlinklist(n,man,l);
joseph(l,n);
}
四、调试分析
1、由于建立的是带头结点的单循环链表,导致输出的结果许多是错的,删除头结点,即建立的是不带头结点的单循环链表解决。
2、由于开始时没有指针指向要开始报数结点后的指针,导致当开始密码是1时不能删除第一个结点,出现输出乱的现象,经检查发现该错误,采用在joseph函数的开始就扫描单循环链表,使指针其指向单循环链表的最后一个结点,以便需要时能删除第一个结点,也就是说,在数结点时后面要跟一个指针,以便当数到要删除那个结点时,通过对后面跟着的指针所指结点的操作能删除数到的结点,这样就解决了这个问题。
这一点也提醒我们,单恋表中的操作,要删除结点,必须有指向其“前驱”结点的指针,否则是不能删除要删除的结点的。
3、由于先删除了结点空间,没有把被删结点中的密码保存,出现得到的密码不是被删结点的密码,而是被删结点下一个结点的密码,导致输出的信息不正确,修改成在删除结点空间前先保存其密码而解决。
4、算法的时间复杂度
设约瑟夫问题中的人数为n,则建立单链表的时间复杂度是Ο(n),约瑟夫问题的求解模块中,要n次出列人,而每次出列人要走m个结点,设密码的平均值为m,则约瑟夫问题求解模块的时间复杂度为Ο(n×
m)。
所以算法的时间复杂度为○(n)。
五、测试结果
第一组:
Input
7
3172484
Output
614723
第二组:
10
529683114710
69724531810
测试通过。
六、用户使用说明
1、本程序的运行环境为windows操作系统下命令执行方式,执行文件为:
exp1.exe;
也可在VC集成环境下执行。
2、运行程序后输入人数n后,按提示依次输入n个密码即可。
输出的是约瑟夫问题的求解过程中出列人的编号。
见下图。
七、附录
源程序文件名清单:
exp1.cpp。
实验结束后上交。
实验一、大整数加法
一、问题描述
给定两个非负整数A和B,计算出A+B的值。
整数A和B的位数可能超过整数类型数据能存储的范围。
要求计算并输出A+B的值。
二、基本要求
1、正确输入两个大整数;
2利用两个单链表存储结构存储两个大整数;
3对存储于单链表的两个大整数,根据数据加法的要求,通过对链表的操作,使两个大整数的和存储于单链表,并考虑尽量使用原单链表存储空间;
4输出两个大整数的和,即输出和单链表中的内容。
三、测试数据
第一组
99999999999999999999
1
第二组
12345678987654321
9876543212345678987654321
第三组
88888888888888888888888888888888
6666666666666666666666666666666666666666
四、实现提示
1、算法思路
(1)正确输入两个整数,由于其整数位数可能超过整数数据类型可以存储的范围,所以要用字符串的数据类型来接受输入的两个整数。
可以在主函数里完成。
(2)对于存储在字符串里的整数,依次根据字符串中从高位到低位的数值位,可以用前插法建立单链表的方法,将整数存储于带头结点的单链表中(每个结点存放一位数字,也可存放多位数字,前者简单一点。
本指导按前者的处理方法描述),这时,从单链表的第一个结点到尾结点依次是从个位到最高位的整数,以便相加运算。
也可依次根据字符串中从低位(字符串的右端)到高位(字符串的左端)的数值位,用后插法建立单链表的方法,将整数存储于带头结点的单链表中。
也可依次根据字符串中从高位(字符串的左端)的数值位到低位(字符串的右端)的数值位,用后插法建立单链表的方法,将整数存储于带头结点的单链表中,这时,从单链表的第一个结点到尾结点依次是从最高位到个位的整数,然后再逆置这个单链表,使从单链表的第一个结点到尾结点依次是从个位到最高位的整数。
以上过程可用一个函数完成。
(3)对两个从单链表的第一个结点到尾结点依次是从个位到最高位存储的两个整数,从第一个结点开始,依次扫描到长度短的单链表的尾结点,每次把扫描到的两个结点中的数值及前面相加留下的进位相加,把和的个位存储到长度长的单链表对应的结点中,同时记录进位;
然后把可能有的进位依次与长单链表还未相加过的结点依次相加,若到最后一个结点相加后仍有进位,则要新增加一个结点,以存放进位。
至此,两个整数的和已经存储在原来长的单链表中了。
这个过程可以一个函数完成。
(4)对于已经存储好的和的单链表,其第一个结点到尾结点依次是和的个位到最高位,要对该单链表进行逆置,这个过程可用以函数完成。
然后可将其单链表中结点的值输出,这也可用一函数完成。
(5)在主函数中要设置相关的数据结构,以存放两个整数和单链表,输入两个整数后,依次可调用单链表初始化模块、建立单链表模块、两个整数相加模块、单链表逆置模块和输出单链表中结点的值的模块。
中间可确定好较长整数所对应的单链表指针,以供两个整数相加模块使用。
2、数据结构
存放输入的整数可用string类型字符串,也可用char类型一维字符数组。
存放整数的单链表中的结点结构可以是:
{intdata;
}*linklist;
3、基本操作
(1)构造一个空的带头结点的单链表l,用单链表中每个结点的数据域存放每一个整数位。
initlist(linklist&
{
该函数可在主函数中调用。
(2)依次根据存放整数的字符串s1中从高位到低位的数值位,前插法建立带表头结点的单链表。
createlist_f(linklistl,strings1)
for(s1中的每一个数字字符)
转化成数值;
存于结点并连接到单链表的头部;
(3)单链表逆置。
以便把单链表转换成所需要的从第一个结点到尾结点依次是从最高位到个位整数(要相反顺序也一样)。
inverse(linklistl)
…
该函数可在主函数或相关函数中调用。
(4)输出单链表中的元素值。
print(linklistl)
该函数可在主函数中调用。
(5)整数相加。
其中l1、l2是存放两个整数的单链表,l是较长整数的单链表。
add(linklistl1,linklistl2,linklistl)
指针指向存放较长整数单链表的第一个结点;
指针指向两个整数单链表的第一个结点;
while(指向两个整数单链表均不空)
计算两个整数单链中的数值和进位的和;
记录进位;
把和的个位存储于较长整数单链表的结点;
各指针均向后移动一个结点;
while(有进位且较长整数单链表不空)
计算较长整数单链表中的数值和进位的和;
指向较长整数单链表的结点指针向后移动一个结点;
if(还有进位)
较长整数单链表增加结点,存放最后的进位。
4、主程序
main()
输入两个整数;
调用相关模块,将单链表初始化后将两个整数存储于单链表;
确定较长整数的单链表;
调用整数相加模块进行整数相加;
调用链表逆置模块对单链表的数位进行逆置;
调用输出模块输出和单链表;
五、测试与输出结果
SampleInput
3
9
SampleOutput
9876543224691357975308642
6666666755555555555555555555555555555554
实验二、栈序列匹配
对于给出的入栈序列和出栈序列,判断这两个序列是否相容。
即能否利用栈操作将入栈序列转换为出栈序列。
二、基本要求
入栈序列和出栈序列均为字符型数据,由键盘输入,其长度不超过10个字符。
若入栈序列和出栈序列相容(即能利用栈操作将入栈序列转换为出栈序列),则输出yes,否则输出no。
在判断栈序列的匹配过程中,输出入栈、出栈的过程和栈中的元素。
输入数据的第一行为一个正整数T,表示测试数据的组数。
然后是T组测试数据。
每组测试数据的输入是在同一行中用一个空格分隔的两个字符串(其长度均不超过10),依次表示入栈序列和出栈序列。
输出格式为每入栈(或)出栈一次输出一行:
push(或pop):
cstack:
栈顶到栈底的序列,其中c为入栈(或)出栈的字符,最后一行个根据入栈序列和出栈序列是否匹配输出yes或no,匹配则输出yes,否则输出no(参见SampleOutput)。
设置链式栈或顺序栈s,作为入栈序列的栈空间,设置top为其栈顶指针(或下标)。
对入栈序列从第一个元素开始考虑入栈,在依次扫描出栈序列元素的过程中进行如下的处理:
若栈空且入栈序列有未入栈的元素,则当前入栈序列中的元素入栈,并输出相应的信息;
若栈不空且栈顶的元素为出栈序列的当前元素,则栈顶元素出栈,并输出相应的信息,否则,若入栈序列有未入栈的元素,则当前入栈序列中的元素入栈,并输出相应的信息;
否则可以确定输入的入栈序列和出栈序列不相容(即不匹配)。
最后判断:
若入栈序列和出栈序列均已扫描完且栈为空,则可以确定输入的入栈序列和出栈序列相容(即匹配)。
typedefstructnode//链式栈s中的结点结构
{chardata;
}StackNode,*LinkStack;
LinkStackpush(LinkStacktop,chare)//入栈操作,e为栈中元素类型
LinkStackpop(LinkStacktop,char*e)//出栈操作,e为指向栈中元素的指针类型,为的使其值在函数外面可用
voidlist(LinkStacktop)//显示栈中元素
intjudge(stringstr1,stringstr2)//判断是否匹配主模块,str1和str2为入栈序列和出栈序列
{栈初始化;
从出栈序列的第一个元素开始;
while(出栈序列还未扫描完)
{if(栈空且入栈序列有未入栈的元素)
当前入栈序列中的元素入栈,并输出相应的信息;
if(若栈不空且栈顶的元素为出栈序列的当前元素)
栈顶元素出栈,并输出相应的信息,
elseif(若入栈序列有未入栈的元素)
else确定输入的入栈序列和出栈序列不相容(即不匹配)。
if(若入栈序列和出栈序列均已扫描完且栈为空)
确定输入的入栈序列和出栈序列相容(即匹配)。
else确定输入的入栈序列和出栈序列不相容(即不匹配)。
intmain()
{输入入栈序列和出栈序列;
调用判断是否匹配主模块judge();
根据其返回的值输出yes或no。
输入:
ABCDEFDCEFAB
输出:
push:
Astack:
A
Bstack:
BA
Cstack:
CBA
Dstack:
DCBA
pop:
Estack:
EBA
Fstack:
FBA
no
ABCDEFACEDBF
B
CB
B
DB
EDB
F
yes
实验三、二叉排序树
输入一个整数关键字序列L,生成一棵用链式存储结构存储的二叉排序树,对该二叉排序树能进行查找和插入结点的操作,并对该二叉排序树中结点的关键字按递增和递减顺