数据结构上机实验指导书.docx
《数据结构上机实验指导书.docx》由会员分享,可在线阅读,更多相关《数据结构上机实验指导书.docx(51页珍藏版)》请在冰点文库上搜索。
数据结构上机实验指导书
管理工程学院信息管理与信息系统教研室
2015年7月
目录
第一部分数据结构课程实验概述3
一.实验目的3
二.实验要求4
2.1实验步骤4
2.2实验报告的内容5
2.3实验报告内容与格式6
2.4考核及评分办法6
三、验证算法的方法7
3.1类C语言与标准C的转换要点7
3.2验证算法的源程序结构11
3.3验证算法的源程序举例11
第二部分上机实验内容16
实验一C语言复习及初步认识16
实验二线性表18
实验三栈和队列31
实验四树42
实验五图49
实验六查找56
实验七排序59
第一部分数据结构课程实验概述
一.实验目的
《数据结构》是计算机专业的主干课程和必修课程之一,其目的是让大家学习、分析和研究数据对象特征,掌握数据组织方法和计算机的表示方法,以便选择合适的数据逻辑结构和存储结构,设计相应的运算操作,把现实世界中的问题转化为计算机内部的表示与处理的方法,要求掌握算法的时间、空间复杂度分析基本技术,培养良好的程序设计风格,掌握进行复杂程序设计的技能。
在计算机科学领域,尤其是在系统软件和应用软件的设计和应用中要用到各种数据结构,因此,掌握数据结构对提高软件设计和程序编制水平有很大的帮助。
《数据结构》课对理论与实践的要求都相当高,并且内容多难度大。
虽然多数数据结构教材都强调了实践的重要性,但比较缺乏供实践练习的材料,很多教材对算法的描述也只是扼要的和概述性的,很多算法都采用类C或类PASCAL语言描述,无法直接上机实现。
针对这种情况,我们编写了这本《数据结构上机实验指导书》。
本书可作为”数据结构”课程的辅助教材,供学生在”数据结构”课程实习时使用,以帮助学生在尽可能短的时间内对数据结构知识的实践与应用有一个比较全面、深入和系统的认识,达到理论与实践相结合的目的。
上机实验是对学生的一种全面综合训练,是与课堂听课、自学和练习相辅相成的必不可少的一个教学环节。
实验目的着眼于原理与应用的结合,使学生学会如何把书上的知识用语解决实际问题,能够理解和运用常用的数据结构,如线性表、栈、队列、树、图、查找表等,并在此基础上建立相应的算法;通过上机实验使学生了解算法和程序的区别,培养学生把算法转换为程序的能力,提高学生解决实际问题的能力;学会分析研究计算机加工的数据结构的特性,以便为应用涉及的数据选择适当的逻辑结构、存储结构及其相应的算法,并初步掌握算法的时间分析和空间分析的技术。
加*号的题目可以选做。
二.实验要求
2.1实验步骤
设计步骤的规范不但可以培养学生科学的工作方法和作风,而且还能有效地减少错误,提高工作效率。
因此必须严格执行良好的实验步骤规范(包括上机操作规范)。
本课程实验的基本步骤是:
2.1.1问题分析
充分地分析和理解问题本身,明确问题要求做什幺。
对问题的描述应避开算法和所涉及的数据类型,而是对所需完成的任务作出明确的回答。
例如;输入、输出数据的类型、值的范围以及形式等。
同时为调试程序准备好测试数据,包含合法的输入数据和非法形式输入的数据。
2.1.2设计和编码
设计即是对问题描述中涉及的操作对象定义相应的数据类型,定义主程序模块和各抽象数据类型;定义相应的存储结构并写出各过程和函数的伪码算法。
在这个过程中,要综合考虑系统功能,使得系统结构清晰、合理、简单和易于调试。
编码即把详细设计的结果进一步求精为程序设计语言程序,写出源程序。
对程序中的疑问应作出记号,以便上机时注意解决。
每个明确的功能模块程序一般不超过60行,程序的每一行不得超过60个字符,否则要进一步划分。
2.1.3上机前程序静态检查
上机前程序静态检查可有效提高调试效率,减少上机调试程序时的无谓错误。
静态检查主要有两种途径:
用一组测试数据手工执行程序;通过阅读或给别人讲解自己的程序而深入全面地理解程序逻辑。
把程序中的明显错误事先排除。
2.1.4上机调试程序
上机实验时要带上《C语言》教材、《数据结构》教材、《数据结构上机实验指导书》,调试最好分模块进行,自底向下,即先调试低层过程或函数。
调试过程中应多动手确定疑点,通过修改程序来证明。
调试正确后,认真整理源程序及其注释,写出或打印出带有完整注释的且格式良好的源程序清单和结果。
2.1.5完成上机实验报告
2.2实验报告的内容
1、需求分析
陈述程序设计的任务,强调程序要解决的问题是什么?
明确规定:
输入的形式和输入值的范围;输出的形式;程序所能达到的功能;测试数据。
2、设计
设计思路:
写出存储结构,主要算法的基本思想。
设计表示:
每个操作及模块的伪码算法。
列出每个过程或函数所调用和被调用的过程或函数,也可以通过调用关系(层次)图表达。
实现注释:
各项功能的实现程度、在完成基本要求的基础上还实现了什么功能。
3、调试分析
调试过程中遇到的主要问题,是如何解决的,对设计和编码的回顾讨论和分析;改进设想;经验和体会等。
4、测试结果
列出测试结果,包括输入和输出。
这里的测试数据应该完整和严格,最好多于需求分析中所列。
5、用户手册
说明如何使用你编写的程序,详细列出每一步操作步骤。
6、附录
即带注释的源程序清单和结果。
除原有注释外再加一些必要的注释和断言(关键语句或函数功能的注释)。
对填空和改错题还要写出正确答案,如果题目规定了测试数据,则结果要包含这些测试数据和运行输出,当然还可以含其它测试数据及其运行输出。
2.3实验报告内容与格式
格式:
按照学院统一要求格式
2.4考核及评分办法
上机实验成绩根据上机考勤、调试情况、实验报告评分,分为五级制:
优、良、中、及格、不及格。
三、验证算法的方法
数据结构教材上的算法都是用类C语言来描述,但要验证算法只能用标准C来验证,所以存在类C语言与标准C的转换及验证算法的源程序编写问题。
3.1类C语言与标准C的转换要点
3.1.1预定义常量和类型的问题
在类C语言的算法中出现了下列常量,验证时就需在源程序中定义:
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR0
#defineINFEASIBLE-1
#defineOVERFLOW-2
#defineintStatus
3.1.2算法描述的变量问题
在类C语言算法(函数)中,辅助变量没有作变量说明,但在验证源程序的函数定义时,需对所有使用的变量(除函数参数外)作说明。
例1:
顺序表的插入算法(类C语言):
StatusListInsert_Sq(SqList&L,intpos,ElemTypee)
{
//在顺序线性表L的第pos个元素之前插入新的元素e,pos为位序
//pos的合法值为1≤pos≤Listlength_Sq(L)+1
if(pos<1||pos>L.length+1)returnERROR;
//插入位置不合法
if(L.length>=L.listsize)
{//当前存储空间已满,增加分配
newbase=(ElemType*)realloc(L.elem,
(L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(!
newbase)exit(OVERFLOW);//存储分配失败
L.elem=newbase;//新基址
L.listsize+=LISTINCREMENT;//增加存储容量
}
q=&(L.elem[pos-1]);//q指示插入位置
for(p=&(L.elem[L.length-1]);p>=q;--p)*(p+1)=*p;
//插入位置及之后的元素右移
*q=e;//插入e
++L.length;//表长增1
returnOK;
}//ListInsert_Sq
验证算法源程序中算法所对应的函数定义:
intListInsert_Sq(SqList*L,intpos,ElemTypee)
{
ElemType*newbase,*p,*q;
if(pos<1||pos>L->length+1)return(-1);
if(L->length>=L->listsize)
{
newbase=(ElemType*)realloc(L->elem,(L->listsize+LISTINCREMENT)*sizeof(ElemType));
if(!
newbase)exit(-1);
L->elem=newbase;
L->listsize+=LISTINCREMENT;
}
q=&((L->elem)[pos-1]);
for(p=&((L->elem)[L->length-1]);p>=q;--p)
*(p+1)=*p;
*q=e;
++L->length;
return
(1);
}
3.1.3算法描述的参数问题
在类C语言算法(函数)中,在形参定义时,以“&”打头的参数作为引用参数,即在函数调用后发生改变的量,但在验证源程序的函数定义时,需对引用参数转换为指针类型,在函数定义内,把引用参数的使用转换为引用参数对象的使用。
例2:
顺序表的插入算法(类C语言):
StatusListInsert_Sq(SqList&L,intpos,ElemTypee)
{
//在顺序线性表L的第pos个元素之前插入新的元素e,pos为位序
//pos的合法值为1≤pos≤Listlength_Sq(L)+1
if(pos<1||pos>L.length+1)returnERROR;
//插入位置不合法
if(L.length>=L.listsize)
{//当前存储空间已满,增加分配
newbase=(ElemType*)realloc(L.elem,
(L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(!
newbase)exit(OVERFLOW);//存储分配失败
L.elem=newbase;//新基址
L.listsize+=LISTINCREMENT;//增加存储容量
}
q=&(L.elem[pos-1]);//q指示插入位置
for(p=&(L.elem[L.length-1]);p>=q;--p)*(p+1)=*p;
//插入位置及之后的元素右移
*q=e;//插入e
++L.length;//表长增1
returnOK;
}//ListInsert_Sq
验证算法源程序中算法所对应的函数定义:
intListInsert_Sq(SqList*L,intpos,ElemTypee)
{
ElemType*newbase,*p,*q;
if(pos<1||pos>L->length+1)return(-1);
if(L->length>=L->listsize)
{
newbase=(ElemType*)realloc(L->elem,(L->listsize+LISTINCREMENT)*sizeof(ElemType));
if(!
newbase)exit(-1);
L->elem=newbase;
L->listsize+=LISTINCREMENT;
}
q=&((L->elem)[pos-1]);
for(p=&((L->elem)[L->length-1]);p>=q;--p)
*(p+1)=*p;
*q=e;
++L->length;
return
(1);
}
3.2验证算法的源程序结构
文件包含预处理
符号常量的定义
类型定义/*确定数据结构*/
返回类型自定义函数名(形式参数表)
/*自定义函数的定义,即算法*/
{
}
main()
{
变量定义;/*定义处理对象*/
建立对象;/*根据存储类型,给变量赋值,以确定具体的处理对象*/
调用自定义函数;/*引用函数对处理对象进行操作,实现算法的功能*/
打印输出;/*给出结果*/
}
3.3验证算法的源程序举例
例3:
顺序表的插入算法的验证方法
顺序表的插入算法:
StatusListInsert_Sq(SqList&L,intpos,ElemTypee)
{
//在顺序线性表L的第pos个元素之前插入新的元素e,pos为位序
//pos的合法值为1≤pos≤Listlength_Sq(L)+1
if(pos<1||pos>L.length+1)returnERROR;
//插入位置不合法
if(L.length>=L.listsize)
{//当前存储空间已满,增加分配
newbase=(ElemType*)realloc(L.elem,
(L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(!
newbase)exit(OVERFLOW);//存储分配失败
L.elem=newbase;//新基址
L.listsize+=LISTINCREMENT;//增加存储容量
}
q=&(L.elem[pos-1]);//q指示插入位置
for(p=&(L.elem[L.length-1]);p>=q;--p)*(p+1)=*p;
//插入位置及之后的元素右移
*q=e;//插入e
++L.length;//表长增1
returnOK;
}//ListInsert_Sq
验证“顺序表的插入算法”的源程序:
//文件包含预处理
#include
#include
//符号常量的定义
#defineLIST_INIT_SIZE5
#defineLISTINCREMENT5
//类型定义(确定数据结构)
typedefintElemType;
typedefstruct{
ElemType*elem;
intlength;
intlistsize;
}SqList;
intInitList_Sq(SqList*L)
{
L->elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!
L->elem)exit(-1);
L->length=0;
L->listsize=LIST_INIT_SIZE;
return
(1);
}
intListInsert_Sq(SqList*L,intpos,ElemTypee)
{
ElemType*newbase,*p,*q;
if(pos<1||pos>L->length+1)return(-1);
if(L->length>=L->listsize)
{
newbase=(ElemType*)realloc(L->elem,(L->listsize+LISTINCREMENT)*sizeof(ElemType));
if(!
newbase)exit(-1);
L->elem=newbase;
L->listsize+=LISTINCREMENT;
}
q=&((L->elem)[pos-1]);
for(p=&((L->elem)[L->length-1]);p>=q;--p)
*(p+1)=*p;
*q=e;
++L->length;
return
(1);
}
voidtraverse(SqListL)
{
inti;
printf("thelistdatais:
\n");
for(i=0;iprintf("%5d",L.elem[i]);
printf("\n");
getch();
}
main()
{
inti;
SqListL;/*定义处理对象*/
InitList_Sq(&L);
/*建立对象:
根据存储类型,给变量赋值,以确定具体的处理对象*/
for(i=1;i<=10;i++)
ListInsert_Sq(&L,i,i+1);
/*调用自定义函数:
引用函数对处理对象进行操作,实现算法的功能*/
traverse(L);/*打印输出:
给出结果*/
}
第二部分上机实验内容
实验一C语言复习及初步认识
一、实验目的
本实验的目的是帮助大家复习C语言的使用方法,特别是指针、结构体的内容,同时也为以后的各个实验做准备。
二、实验内容
1、请编写函数intfun(int*a,int*b),函数的功能是判断两个指针a和b所指存储单元的值的符号是否相同;若相同函数返回1,否则返回0。
这两个存储单元中的值都不为0。
在主函数中输入2个整数、调用函数fun、输出结果。
2、计算1+2+3+……+100,要求用指针进行设计。
即设计函数intfun(int*n)实现求1+2+3+……+*n,在主函数中输入、调用、输出结果。
3、请编写函数intfun(int*a,,int*max),函数的功能是求数组a中最大数的值。
在主函数中输入10个整数、调用函数fun、输出结果。
4、请编写函数fun(int*a,intn,int*odd,int*even),函数的功能是分别求出数组a中所有奇数之和和所有偶数之和。
形参n给出数组中数据的个数;利用指针odd和even分别返回奇数之和和偶数之和。
在主函数中输入10个整数、调用函数fun、输出结果。
5、请编写函数intfun(int*a,int*b,intn),函数的功能是把数组a中所有为偶数的数,放在另一个数组中b。
在主函数中输入10个整数、调用函数fun、输出结果。
6、请编写函数intfun(int*a,,intn),函数的功能是把数组a中最大数和最小数交换。
在主函数中输入10个整数、调用函数fun、输出结果。
7、请编写函数intfun(inta[4][4]),函数的功能是把矩阵a转置。
在主函数中输入、调用函数fun、输出结果。
8、请编写函数intfun(char*a),函数的功能是分别求出字符串a的长度。
在主函数中输入1个字符串、调用函数fun、输出结果。
9、设计一个可进行复数运算的演示程序。
要求:
实现下列六种基本运算:
1)由输入的实部和虚部生成一个复数;2)两个复数求和;3)两个复数求差;4)两个复数求积;5)从已知复数中分离出实部;6)从已知复数中分离出虚部。
运算结果以相应的复数或实数的表示形式显示。
10、有5个学生,每个学生的数据包括学号、姓名、3门课的成绩,从键盘输入5个学生数据,要求打印出3门课总平均成绩,以及最高分的学生的数据。
要求:
用input函数输入5个学生数据,用average函数求总平均分;用max函数找出最高分的学生数据;总平均分和最高分学生的数据都在主函数中输出。
实验二线性表
一、实验目的
1.掌握数据结构中表的基本概念。
2.熟练掌握线性表的基本操作,插入、删除、查找,以及线性表合并等运算在顺序存储结构和链接存储结构上的实现。
3.熟练掌握链表的各种操作和应用。
二、实验内容
顺序表的基本运算的算法:
创建顺序表:
输出顺序表;插入运算;删除运算;查找运算
单链表的基本运算的算法:
创建一个单链表;输出一个单链表;求单链表的长度;查找第I个结点;插入一个结点;删除一个结点;
1、设有一个顺序表A,包含n个元素,要求写出一个将该表逆置的算法,并只允许在原表的存储空间外再增加一个附加的工作单元。
(根据题目完善源程序)
#include
#defineMaxLen50
typedefintelemtype;
structdatatype
{elemtype*elem;
intlength;
};
typedefstructdatatypesqlist;
voidcreate(sqlist*a)
{
inti,n;
a->elem=(elemtype*)malloc(MaxLen*sizeof(elemtype));
printf("创建一个顺序表\n");
printf("输入元素个数\n");
scanf("%d",&a->length);
for(i=0;ilength;i++)
{
printf("输入第%d个元素值:
",i+1);
scanf("%d",a->elem+i);
}
}
voidinvert(sqlist*a)
{
intm=a->length/2,i;
elemtypetemp;
for(i=0;i{
temp=;
*(a->elem+i)=;
=temp;
}
}
voiddisp(sqlist*a)
{inti;
for(i=0;ilength;i++)
printf("%5d:
%d\n",i+1,*(a->elem+i));
getch();
}
voidmain()
{
sqlista;
create(&a);
disp(&a);
invert(&a);
disp(&a);
}
创建一个顺序表
输入元素个数:
5
输入第1个元素值:
2
输入第2个元素值:
6
输入第3个元素值:
3
输入第4个元素值:
1
输入第5个元素值:
8
输出一个顺序表
输出一个顺序表
2、有一个单链表的第一个结点指针为head,编写一个函数将该单链表逆置,即最后一个结点变成第一个结点,原来倒数第二个结点变成第二个结点。
在逆置中不能建立新的单链表(根据题目填空完善程序)
#include
#include
#defineNULL0
typedefintelemtype;
typedefstructlinknode
{
elemtypedata;
structlinknode*next;
}nodetype;
nodetype*create()
{
elemtyped;
nodetype*h,*s,*t;
inti=1;
h=NULL;
printf("建立一个单链表\n");
while
(1)
{
printf("输入第%d节点data域值:
",i);
scanf("%d",&d);
if(d==0);/*以0表示输入结束*/
if(i==1)/*建立第一个结点*/
{
h=;
h->data=d;h->next=NULL;t=h;
}
else
{
s=(node