数据结构验证性实验指导书.docx
《数据结构验证性实验指导书.docx》由会员分享,可在线阅读,更多相关《数据结构验证性实验指导书.docx(96页珍藏版)》请在冰豆网上搜索。
数据结构验证性实验指导书
《数据结构基础》
课外实验指导书
计算机学院
2015年9月
课外学时:
16
要求:
完成4个课外实验(实验题目自选),填写实验报告
注意:
到教材科购买计算机学院上机实验报告
考核:
实验报告成绩作为平时成绩的一部分
提交时间:
第10周交给各班班长
地点:
鉴主1108
一、上机实验概述
上机实验是对学生的一种全面综合训练,是与课堂听讲、自学和练习相辅相成的必不可少的一个教学环节。
通常,实验题中的问题比平时的习题复杂得多,也更接近实际。
实验着眼于原理与应用的结合点,使读者学会如何把书上学到的知识用于解决实际问题,培养软件工作所需要的动手能力;另一方面,能使书上的知识变“活”,起到深化理解和灵活掌握教学内容的目的。
平时的练习较偏重于如何编写功能单一的“小”算法,而实验题是软件设计的综合训练,包括问题分析、总体结构设计、用户界面设计、程序设计基本技能和技巧,多人合作,以至一整套软件工作规范的训练和科学作风的培养。
此外,还有很重要的一点是:
机器是比任何教师都严厉的检查者。
每个实验题采取了统一的格式,由问题描述、基本要求、测试数据、实现提示和选做内容五个部分组成。
问题描述旨在为读者建立问题提出的背景环境,指明问题“是什么”。
基本要求则对问题进一步求精,划出问题的边界,指出具体的参量或前提条件,并规定该题的最低限度要求。
测试数据部分旨在为检查学生上机作业提供方便,在完成实验题时应自己设计完整和严格的测试方案,当数据输入量较大时,提倡以文件形式向程序提供输入数据。
在实现提示部分,对实现中的难点及其解法思路等问题作了简要提示。
选做部分向那些尚有余力的读者提出了更严峻的挑战,同时也能开拓其他读者的思路,在完成基本要求时力求避免就事论事的不良思想方法,尽可能寻求具有普遍意义的解法,使得程序结构合理,容易修改扩充。
不难发现,这里与传统的做法不同,题目设计得非常详细。
会不会限制读者的想象力,影响创造力的培养呢?
回答是:
软件发展的一条历史经验就是要限制程序设计者在某些方面的创造性,从而使其创造能力集中地用到特别需要创造性的环节之上。
实验题目本身就给出了问题说明和问题分解求精的范例,使读者在无形中学会模仿,它起到把读者的思路引上正轨的作用,避免坏结构程序和坏习惯,同时也传授了系统划分方法和程序设计的一些具体技术,保证实现预定的训练意图,使某些难点和重点不会被绕过去,而且也便于教学检查。
题目的设计策略是:
一方面使其难度和工作量都较大,另一方面给读者提供的辅助和可以模仿的成份也较多。
当然还应指出的是,提示的实现方法未必是最好的,读者不应拘泥于此,而应努力开发更好的方法和结构。
实验要有严格的规范(见下一节)。
一种普遍存在的错误观念是,调试程序全凭运气。
学生花两个小时的上机时间只找出一个错误,甚至一无所获的情况是常见的。
其原因在于,很多人只认识到找错误,而没有认识到努力预先避免错误的重要性,也不知道应该如何努力。
实际上,结构不好、思路和概念不清的程序可能是根本无法调试正确的。
严格按照实验步骤规范进行实验不但能有效地避免上述种种问题,更重要的是有利于培养软件工作者不可缺少的科学工作方法和作风。
二、实验步骤
随之计算机性能的提高,它所面临的软件开发的复杂度也日趋增加。
然而,编制一个10,000行的程序的难度绝不仅仅是一个5,000行的程序两倍,因此软件开发需要系统的方法。
一种常用的软件开发方法,是将软件开发过程划分为分析、设计、实现和维护四个阶段。
虽然数据结构课程中的实验题的复杂度远不如(从实际问题中提出来的)一个“真正的“软件,但为了培养一个软件工作者所应具备的科学工作的方法和作风,我们制订了如下所述完成实验的五个步骤:
(一)问题分析和任务定义
通常,实验题目的陈述比较简洁,或者说是有模棱两可的含义。
因此,在进行设计之前,首先应该充分地分析和理解问题,明确问题要求做什么?
限制条件是什么。
注意本步骤强调的是做什么?
而不是怎么做。
对问题的描述应避开算法和所涉及的数据类型,而是对所需完成的任务作出明确的回答。
例如:
输入数据的类型、值的范围以及输入的形式;输出数据的类型、值的范围及输出的形式;若是会话式的输入,则结束标志是什么?
是否接受非法的输入?
对非法输入的回答方式是什么等。
这一步还应该为调试程序准备好测试数据,包括合法的输入数据和非法形式的输入数据。
(二)数据类型和系统设计在设计这一步骤中需分概要设计和详细设计两步实现。
概要设计指的是,对问题描述中涉及的操作对象定义相应的数据类型,并按照以数据结构为中心的原则划分模块,定义主程序模块和各抽象数据类型;
详细设计则为定义相应的存储结构并写出各函数的伪码算法。
在这个过程中,要综合考虑系统功能,使得系统结构清晰、合理、简单和易于调试,抽象数据类型的实现尽可能做到数据封装,基本操作的规格说明尽可能明确具体。
作为概要设计的结果,应写出每个抽象数据类型的定义(包括数据结构的描述和每个基本操作的规格说明),各个主要模块的算法,并画出模块之间的调用关系图。
详细设计的结果是对数据结构和基本操作的规格说明作出进一步的求精,写出数据存储结构的类型定义,按照算法书写规范用类C语言写出函数形式的算法框架。
在求精的过程中,应尽量避免陷入语言细节,不必过早表述辅助数据结构和局部变量。
(三)编码实现和静态检查编码是把详细设计的结果进一步求精为程序设计语言程序。
程序的每行不要超过60个字符。
每个函数体,即不计首部和规格说明部分,一般不要超过40行,最长不得超过60行,否则应该分割成较小的函数。
要控制if语句连续嵌套的深度。
如何编写程序才能较快地完成调试是特别要注意的问题。
对于编程很熟练的读者,如果基于详细设计的伪码算法就能直接在键盘上输入程序的话,则可以不必用笔在纸上写出编码,而将这一步的工作放在上机准备之后进行,即在上机调试之前直接用键盘输入。
然而,不管你是否写出编码的程序,在上机之前,认真的静态检查是必不可少的。
多数初学者在编好程序后处于以下两种状态之一:
一种是对自己的“精心作品“的正确性确信不疑;另一种是认为上机前的任务已经完成,纠查错误是上机的工作。
这两种态度是极为有害的。
事实上,非训练有素的程序设计者编写的程序长度超过50行时,极少不含有除语法错误以外的错误。
上机动态调试决不能代替静态检查,否则调试效率将是极低的。
静态检查主要有两种方法,一是用一组测试数据手工执行程序(通常应先分模块检查);二是通过阅读或给别人讲解自己的程序而深入全面地理解程序逻辑,在这个过程中再加入一些注解和断言。
如果程序中逻辑概念清楚,后者将比前者有效。
(四)上机准备和上机调试
上机准备包括以下几个方面:
(1)高级语言文本(体现于编译程序用户手册)的扩充和限制。
例如,常用的BorlandC(C++)和MicrosoftC(C++)与标准C(C++)的差别,以及相互之间的差别。
(2)如果使用C或C++语言,要特别注意与教科书的类C语言之间的细微差别。
(3)熟悉机器的操作系统和语言集成环境的用户手册,尤其是最常用的命令操作,以便顺利进行上机的基本活动。
(4)掌握调试工具,考虑调试方案,设计测试数据并手工得出正确结果。
上机调试程序时要带一本高级语言教材或手册。
调试最好分模块进行,自底向上,即先调试低层函数。
必要时可以另写一个调用驱动程序。
这种表面上麻烦的工作实际上可以大大降低调试所面临的复杂性,提高调试工作效率。
调试中遇到的各种异常现象往往是预料不到的,此时不应“冥思苦想”,而应动手确定疑点,通过修改程序来证实它或绕过它。
调试正确后,认真整理源程序及其注释,印出带有完整注释的且格式良好的源程序清单和结果。
(五)总结和整理实验报告
实验一线性表及其应用
一、实验目的
1.熟悉C语言的上机环境,进一步掌握C语言的结构特点。
2.掌握线性表的顺序存储结构的定义及C语言实现。
3.掌握线性表在顺序存储结构即顺序表中的各种基本操作。
二、实验内容
顺序线性表的建立、插入及删除。
三、实验步骤
1.建立含n个数据元素的顺序表并输出该表中各元素的值及顺序表的长度。
2.利用前面的实验先建立一个顺序表L={21,23,14,5,56,17,31},然后在第i个位置插入元素68。
四、实现提示
1.由于C语言的数组类型也有随机存取的特点,一维数组的机内表示就是顺序结构。
因此,可用C语言的一维数组实现线性表的顺序存储。
在此,我们利用C语言的结构体类型定义顺序表:
#defineMAXSIZE 1024
typedef int elemtype; /* 线性表中存放整型元素 */
typedefstruct
{elemtypevec[MAXSIZE];
intlen; /* 顺序表的长度 */
}sequenlist;
将此结构定义放在一个头文件sqlist.h里,可避免在后面的参考程序中代码重复书写,另外在该头文件里给出顺序表的建立及常量的定义。
2.注意如何取到第i个元素,在插入过程中注意溢出情况以及数组的下标与位序(顺序表中元素的次序)的区别。
五、思考与提高
1.如果按由表尾至表头的次序输入数据元素,应如何建立顺序表。
2.在main函数里如果去掉L=&a语句,会出现什么结果?
六、完整参考程序
1.顺序线性表的建立、插入及删除。
#include
#include
#defineMAX30//定义线性表的最大长度
enumBOOL{False,True};//定义BOOL型
typedefstruct{
charelem[MAX];//线性表
intlast;//last指示当前线性表的长度
}sqlist;
voidinitial(sqlist&);//初始化线性表
BOOLinsert(sqlist&,int,char);//在线性表中插入元素
BOOLdel(sqlist&,int,char&);//在线性表中删除元素
intlocate(sqlist,char);//在线性表中定位元素
voidprint(sqlist);//显示线性表中所有元素
voidmain()
{sqlistS;//S为一线性表
intloc,flag=1;
charj,ch;
BOOLtemp;
printf("本程序用来实现顺序结构的线性表。
\n");
printf("可以实现查找、插入、删除等操作。
\n");
initial(S);//初始化线性表
while(flag)
{printf("请选择:
\n");
printf("1.显示所有元素\n");
printf("2.插入一个元素\n");
printf("3.删除一个元素\n");
printf("4.查找一个元素\n");
printf("5.退出程序\n");
scanf("%c",&j);
switch(j)
{case'1':
print(S);break;//显示所有元素
case'2':
{printf("请输入要插入的元素(一个字符)和插入位置:
\n");
printf("格式:
字符,位置;例如:
a,2\n");
scanf("%c,%d",&ch,&loc);//输入要插入的元素和插入的位置
temp=insert(S,loc,ch);//插入
if(temp==False)printf("插入失败!
\n");//插入失败
else{printf("插入成功!
\n");print(S);}//插入成功
break;
}
case'3':
{printf("请输入要删除元素的位置:
");
scanf("%d",&loc);//输入要删除的元素的位置
temp=del(S,loc,ch);//删除
if(temp==True)printf("删除了一个元素:
%c\n",ch);//删除成功
elseprintf("该元素不存在!
\n");//删除失败
print(S);
break;
}
case'4':
{printf("请输入要查找的元素:
");
scanf("%c",&ch);//输入要查找的元素
loc=locate(S,ch);//定位
if(loc!
=-1)printf("该元素所在位置:
%d\n",loc+1);//显示该元素位置
elseprintf("%c不存在!
\n",ch);//当前元素不存在
break;
}
default:
flag=0;printf("程序结束,按任意键退出!
\n");
}
}
getch();
}
voidinitial(sqlist&v)
{//初始化线性表
inti;
printf("请输入初始线性表长度:
n=");//输入线性表初始化时的长度
scanf("%d",&v.last);
printf("请输入从1到%d的各元素(字符),例如:
abcdefg\n",v.last);
getchar();
for(i=0;i}
BOOLinsert(sqlist&v,intloc,charch)
{//插入一个元素,成功返回True,失败返回False
inti;
if((loc<1)||(loc>v.last+1))
{printf("插入位置不合理!
\n");//位置不合理
returnFalse;
}
elseif(v.last>=MAX)//线性表已满
{printf("线性表已满!
\n");
returnFalse;
}
else{for(i=v.last-1;i>=loc-1;i--)v.elem[i+1]=v.elem[i];//其后元素依次后移
v.elem[loc-1]=ch;//插入元素
v.last++;//线性表长度加一
returnTrue;
}
}
BOOLdel(sqlist&v,intloc,char&ch)
{//删除一个元素,成功返回True,并用ch返回该元素值,失败返回False
intj;
if(loc<1||loc>v.last)//删除位置不合理
returnFalse;
else{ch=v.elem[loc-1];//ch取得该元素值
for(j=loc-1;jv.last--;//线性表长度减一
returnTrue;
}
}
intlocate(sqlistv,charch)
{//在线性表中查找ch的位置,成功返回其位置,失败返回-1
inti=0;
while(i=ch)i++;//当前位置后移,直到找到为止
if(v.elem[i]==ch)//找到当前元素
returni;
elsereturn(-1);
}
voidprint(sqlistv)//显示当前线性表所有元素
{inti;
for(i=0;iprintf("\n");
}
实验二线性表及其应用
一、实验目的
1.熟悉C语言的上机环境,进一步掌握C语言的结构特点。
2.掌握线性表的链式存储结构——单链表的定义及C语言实现。
3.掌握线性表在链式存储结构——单链表中的各种基本操作。
二、实验内容
链式线性表的建立、插入及删除。
三、实验步骤
建立一个带头结点的单链表,结点的值域为整型数据。
要求将用户输入的数据按尾插入法来建立相应单链表。
四、实现提示
单链表的结点结构除数据域外,还含有一个指针域。
用C语言描述结点结构如下:
typedefintelemtype;
typedefstructnode
{elemtypedata; //数据域
structnode*next;//指针域
}linklist;
注意结点的建立方法及构造新结点时指针的变化。
构造一个结点需用到C语言的标准函数malloc(),如给指针变量p分配一个结点的地址:
p=(linklist*)malloc(sizeof(linklist));该语句的功能是申请分配一个类型为linklist的结点的地址空间,并将首地址存入指针变量p中。
当结点不需要时可以用标准函数free(p)释放结点存储空间,这时p为空值(NULL)。
五、完整参考程序
1.链式线性表的建立、插入及删除。
#include
#include
#include
#defineLENsizeof(LNode)//定义LEN为一个节点的长度
enumBOOL{False,True};//定义BOOL型
typedefstructnode
{chardata;//数据域
structnode*next;//指向下一个节点的指针
}LNode,*LinkList;
voidCreatList(LinkList&,int);//生成一个单链表
BOOLListInsert(LinkList&,int,char);//在单链表中插入一个元素
BOOLListDelete(LinkList&,int,char&);//在单链表中删除一个元素
BOOLListFind_keyword(LinkList,char,int&);//按关键字查找一个元素
BOOLListFind_order(LinkList,char&,int);//按序号查找一个元素
voidListPrint(LinkList);//显示单链表所有元素
voidmain()
{LinkListL;
BOOLtemp;
intnum,loc,flag=1;
charj,ch;
printf("本程序实现链式结构的线性表的操作。
\n");
printf("可以进行插入,删除,定位,查找等操作。
\n");
printf("请输入初始时链表长度:
");//输入生成单链表时的元素个数
scanf("%d",&num);
CreatList(L,num);//生成单链表
ListPrint(L);
while(flag)
{printf("请选择:
\n");
printf("1.显示所有元素\n");//显示链表元素
printf("2.插入一个元素\n");//插入链表元素
printf("3.删除一个元素\n");//删除链表元素
printf("4.按关键字查找元素\n");//按关键字查找
printf("5.按序号查找元素\n");//按序号查找
printf("6.退出程序\n");//退出
scanf("%c",&j);
switch(j)
{case'1':
ListPrint(L);break;
case'2':
{printf("请输入元素(一个字符)和要插入的位置:
\n");
printf("格式:
字符,位置;例如:
a,3\n");
scanf("%c,%d",&ch,&loc);//输入要插入的元素和要插入的位置
temp=ListInsert(L,loc,ch);//插入
if(temp==False)printf("插入失败!
\n");//插入失败
elseprintf("插入成功!
\n");//成功插入
ListPrint(L);
break;
}
case'3':
printf("请输入要删除的元素所在位置:
");
scanf("%d",&loc);//输入要删除的节点的位置
temp=ListDelete(L,loc,ch);//删除
if(temp==False)printf("删除失败!
\n");//删除失败
elseprintf("成功删除了一个元素:
%c\n",ch);//删除成功,显示该元素
ListPrint(L);
break;
case'4':
if(L->next==NULL)//链表为空
printf("链表为空!
\n");
else{printf("请输入要查找的元素(一个字符):
");
scanf("%c",&ch);//输入要查找的元素
temp=ListFind_keyword(L,ch,loc);//按关键字查找
if(temp==False)printf("没有找到该元素!
\n");//查找失败
elseprintf("该元素在链表的第%d个位置。
\n",loc);
//成功查找,显示该元素位置
}
break;
case'5':
if(L->next==NULL)//链表为空
printf("链表为空!
\n");
else{printf("请输入要查找的位置:
");
scanf("%d",&loc);//输入要查找的元素的位置
temp=ListFind_order(L,ch,loc);//按序号查找
if(temp==False)printf("该位置不存在!
\n");//查找失败
elseprintf("第%d个元素是:
%c\n",loc,ch);
//成功查找,显示该元素
}
break;
default:
flag=0;printf("程序结束,按任意键退出!
\n");
}
}
getch();
}
voidCreatList(LinkList&v,intn)
{//生成一个带头结点的有n个元素的单链表
inti;
LinkListp;
v=(LinkList)malloc(LEN);//生成头结点
v->next=NULL;
printf("请输入%d个字符:
例如:
abcdefg\n",n);
getchar();
for(i=n;i>0;--i)
{p=(LinkList)malloc(LEN);//生成新结点
scanf("%c",&p->data);
p->next=v->next;
v->next=p;
}
}
BOOLListInsert(LinkList&v,inti,chare)
{//在单链表的第i各位置插入元素e,成功返回True,失败返回False
LinkListp,s;
intj=0;
p=v;
while(p&&jnext;++j;}//查找第i-1个元素的位置
if(!
p||j>i-1)returnFalse;//没有找