《数据结构》实验指导手册.docx
- 文档编号:24945929
- 上传时间:2023-06-03
- 格式:DOCX
- 页数:73
- 大小:235.19KB
《数据结构》实验指导手册.docx
《《数据结构》实验指导手册.docx》由会员分享,可在线阅读,更多相关《《数据结构》实验指导手册.docx(73页珍藏版)》请在冰豆网上搜索。
《数据结构》实验指导手册
《数据结构》实验指导手册
实验1预备实验
实验2顺序表的基本操作
实验3链表的基本操作
实验4顺序表和链表的综合——求两个集合的交和并
实验5栈的基本操作及应用
实验6队列的基本操作及应用
实验7栈和队列的综合应用——迷宫问题
实验8二叉链表的生成以及二叉树的遍历
实验9二叉树的应用——家谱的管理
实验10图的相关算法
实验11各类查找算法实现及比较
实验12各类排序算法的实现及比较
实验1预备实验
实验时间:
年月日实验地点:
软件实验室实验成绩:
【实验类型】验证型实验
【实验要求】
1.实验前做好实验准备,携带C语言相关书籍便于查阅;
2.实验结束后,书写实验小结;
3.将完成的实验报告交给任课教师。
【实验目的】
1.进一步熟悉并掌握C语言中有关结构体类型定义和结构体变量成员引用的等内容;
2.进一步熟悉并掌握C语言中对文件的读写操作;
3.掌握用typedef的方法进行类型定义。
【实验分析及实验内容】
调试运行下面的程序1和2,注意结构体变量的定义和结构体成员的引用,掌握typedef的正确使用。
完成实验3和4。
程序1:
定义结构体类型,定义和引用结构体变量
#include
#defineMaxsize100
#defineN10
structlist
{
intelem[100];
intlast;
};
voidmain()
{
structlistLa;//结构体变量
structlist*PL;//结构体指针变量
PL=&La;//让指针PL指向变量La
inti;
La.last=-1;//将结构体变量La的last分量置一个初值
//给结构体变量La的elem分量赋值
for(i=0;i { La.elem[i]=2*i+1; La.last++; } //输出变量La的elem分量中的元素 for(i=0;i printf("%d\t",La.elem[i]); printf("\n"); //运用La的last分量替换循环条件 for(i=0;i<=La.last;i++) printf("%d\t",La.elem[i]); printf("\n"); //运用指针变量PL访问变量La的分量 for(i=0;i<=PL->last;i++) printf("%d\t",PL->elem[i]); printf("\n"); } 比较上述程序中的3次输出的结果,发现了什么? 程序2.利用typedef定义新类型,实现上述程序 #include #defineMaxsize100 #defineN10 typedefintElemtype; typedefstructlist { Elemtypeelem[100]; intlast; }List,*PList; voidmain() { ListLa; PListPL; inti; PL=&La; La.last=-1;//将结构体变量La的last分量置一个初值 //给结构体变量La的elem分量赋值 for(i=0;i { La.elem[i]=2*i+1; La.last++; } //输出变量La的elem分量中的元素 for(i=0;i printf("%d\t",La.elem[i]); printf("\n"); //运用La的last分量替换循环条件 for(i=0;i<=La.last;i++) printf("%d\t",La.elem[i]); printf("\n"); //运用指针变量PL访问变量La的分量 for(i=0;i<=PL->last;i++) printf("%d\t",PL->elem[i]); printf("\n"); } 在上述程序中,利用typedef定义了类型Elemtype,定义了结构体类型List和结构体指针类型PList,请查阅相关资料理解上述类型定义的含义。 3.修改上述程序,定义一个新变量x,其值由键盘输入,并将输入的值依次赋值到结构体变量La.elem数组中,尝试将for循环换成while循环,将循环执行条件(i 4.创建一个文件data.txt,文件中的数据为1357911131719,通过文件的读写操作将该文件中的数据依次读入到变量x中,并依次放到结构体变量La的数组分量elem中,然后对该数组的元素数值执行加倍操作,即原来的数值是5,则现在要变成25。 输出变化后的La的elem分量的值,并将这些值写在源文件data.txt的后面,即该文件中的数据是: 135791113151719 29254981121169225289361 实验2顺序表的操作 实验时间: 年月日实验地点: 软件实验室实验成绩: 【实验类型】验证型实验 【实验要求】 1.实验前做好实验准备,清楚实验内容和实验目的; 2.实验结束后,书写实验小结; 3.将完成的实验报告交给任课教师。 【实验目的】 1.熟悉并掌握顺序表的定义、顺序表的属性; 2.熟悉并掌握顺序表的插入、删除、查询、访问元素等操作的思想和实验方法; 3.充分理解顺序存储数据结构的概念,逐步培养解决实际问题的能力。 【实验分析和实验内容】 本实验目的是熟悉顺序表的基本操作,因此掌握顺序表的基本定义,熟悉相关操作的思想是首要内容。 基本概念: 1)线性表(linearList): 线性表是n个类型相同的数据元素的有限序列,对n>0,除第一个元素无直接前驱、最后一个元素无直接后继外,其余的每个数据元素只有一个直接前驱和一个直接后继。 2)顺序表: 采用顺序存储结构存放的线性表,使得线性表中在逻辑结构上相邻的数据元素存储在存储结构上也是相邻的。 顺序表的描述如下: #defineMAXSIZE100 typedefstruct { Elemtypeelem[MAXSIZE]; intlast; }SeqList; 上面用typedef定义的数据类型SeqList我们可以理解成为是顺序表类型,即具有该类型的变量就是一个顺序表。 SeqListLa;//此语句的含义可以理解为定义了一个顺序表La; 顺序表La由两个部分构成: 一个是数组L.elem,是用来存放数据的;另一个是整型变量L.last,用来标记顺序表的最后一个元素(表尾元素)在数组L.elem中的位置(下标)。 SeqList*L;//定义了一个顺序表类型的指针变量L。 与其他类型的指针变量一样,//L只有在“有所指向”的前提下才能访问。 执行如下操作: L=&La;//指针变量L指向了顺序表变量La,我们可以通过L来引用La的成员如下: L->elem[i]//访问L所指向的顺序表的元素,与La.elem[i]同。 L->last//L所指向的顺序表的表尾位置,与La.last同。 在对顺序表(设为La)进行操作之前,必须保证顺序表在“可操作”状态,那么什么状态是“可操作”的状态呢? 为了理解方便,我们来看几个图: 图2.1所示的顺序表有5个元素A,B,C,D,E: 这些元素分别存储在数组La.elem[0]~La.elem[4]中,表尾元素是La.elem[4],所以La.last的值等于4 La.elem: A B C D E 0 1 2 3 4 …… …… MAXZISE-1 La.last=4 图2.1有5个元素的顺序表 图2.2所示的顺序表中有4个元素A,B,C,D,存储在数组La.elem[0]~La.elem[3]中,La.last的值等于3. La.elem: A B C D 0 1 2 3 4 …… …… MAXZISE-1 La.last=3 图2.2有4个元素的顺序表 观察上面的图1和图2,容易看出: 1)顺序表的元素从下标0开始依次存储在数组La.elem中; 2)顺序表La的表尾元素就是La.elem[La.last]; 此外,我们也可以发现,图2就是将图1中的元素E删除后的状态。 当删除的过程一直进行下去,表中只有1个元素的时候,如图2.3所示: La.elem: A 0 1 2 3 4 …… …… MAXZISE-1 La.last=0 图2.3只有1个元素的顺序表 那么当所有元素都删除后,顺序表La就是一个空表了,数组La.elem中没有存储元素,而La.last的值呢? 很显然,La.last=-1。 所以我们判定一个表是否是空表的条件就是去看是否La.last==-1。 那么如何去判断一个表是否是满的呢? 看图2.4。 La.elem: A B C D E …… …… Z 0 1 2 3 4 …… …… MAXZISE-1 La.last=MAXSIZE-1 图2.4满顺序表 一个顺序表是满表,就是数组La.last中的空间都已经存储了数据,没有空间可以村粗其他元素了,即是说La.elem[0]~La.elem[MAXSIZE-1]都存放了数据,所以表尾元素的位置La.last=MAXSIZE-1。 所以判断顺序表是否是满的条件就是去看是否La.last==MAXSIZE-1。 对于顺序表La而言,其表尾标志La.last的值是等于当前顺序表的表长n-1,其变换范围是-1≦La.last≦MAXSIZE-1,而对表进行有效操作时,表通常是三种状态中的一种: a)空表(La.last==-1);b)非空非满表(-1 初始时,顺序表应该是一个空表,通过不断地插入元素,表的状态从a)变换到b),当表满时状态转到c),此时不能够再执行插入操作,类似地,删除元素的过程也是如此,只不过删除的最终过程是表为空表。 上述的这几种状态都可称为“可操作状态”。 下面要开始具体算法的编写了。 第一个要编写的函数是初始化。 这个看似不起眼,语句也不多的算法,却起着非常大的作用,就如同参加田径比赛的时候,运动员在听到起跑命令前要做好起跑准备,蹲伏在起跑器一样。 在以后的所有数据结构的算法描述中,第一个要描述算法都是初始化,这个很重要哦! 要记住! 1.顺序表的初始化InitList(L): 初始化的过程就是设立一个空表的过程。 所谓空表就是没有元素的表,没有元素,那么最后一个元素的标志位置就应该<0。 因此,初始化的过程很简单: voidInitList(SeqList*L) { L->last=-1;//空表标志,也是一个起始位置 } 2.建表CreatList(L,n)。 建立一个顺序表La,表中有n个元素,分别存储在La.elem[0]~La.elem[n-1]中,建立过程如下: voidCreatList(SeqList*L,intn)//创建一个表长为n的顺序表 { inti; charc; for(i=0;i { scanf("%c",&c);//假设线性表的元素为字符 L->elem[i]=c; L->last++; } } 3.输出Output(L)。 输出顺序表中元素: 无论顺序表La的数组分量La.elem存储了多少元素,La的“有效”元素只存储在La.elem[0]~La.elem[La.last]中,将它们依次输出即可。 voidOutput(SeqListL) { inti=0; while(i<=L.last) { printf("%c\t",L.elem[i]); i++; } } 完成了初始化、创建表和输出的算法,接下来该做的事情就是写程序检验一下算法啦! 也就是编写主函数main,完成对上述三个算法的调用! 4.编写主函数main(),调用上述三个函数,实现顺序表La的建立和数据输出。 voidmain() { 定义相关变量 初始化一个顺序表 创建一个顺序表 输出 } 对于主函数中的框架的组织,思路要清晰! 实验内容1: 请大家上机调试完成上述的操作1~4。 5.置空表ClearList()。 置空表的含义是不去管原来的表是空还是非空,强制将其置为空表的过程。 如何去完成这件事呢? 是不是需要依次的将原来的表中的元素删除呢? 回答是NO。 回想前面的一些过程我们知道,对于任何的一个“可操作”的顺序表La,其表尾标志的变换范围是: -1≦La.last≦MAXSIZE-1。 这也就是说,表是什么状态我们通常是通过La.last这个量来衡量的,如果La.last==-1,该表是空表;否则就是非空的表,当La.last==MAXSIZE-1,该表就是满表。 而置空表的就是强制使得表的状态满足La.last==-1即可,因此该算法的表现形式与初始化完全一致: voidClearList(SeqList*L) { L->last=-1;//强制将表尾的位置置为-1 } 这件事情完成了,也许有人会问,可不可以通过设置La.last==MAXSIZE-1将表设置为满表? 很有意思的一个问题,如果你想知道答案,那就动手编写个试一试就知道。 6.求表长ListLength(L)。 求出顺序表中有效元素的个数。 这个问题问得很简单,而且好像也很容易就能够回答出,但是在算法实现的时候就是会出错,错在哪里了呢? 顺序表中能够存储的元素个数最多不超过MAXSIZE个,这从顺序表的定义中很容易就可以理解了,但是很多的时候,表中的元素个数是小于MAXSIZE的。 当对一个顺序表执行了若干次的插入、删除操作后,问表中到底有几个元素? 比如目前有一道门,初始时门内是空的,接着不时地有人进门去,也会有人走出来,几番回合后,问门内尚有几人? (进去数一数不就行了嘛! 哈哈哈! )对于顺序表而言,我们不需要“亲自”去数元素个数,因为我们有“秘书”。 谁是“秘书”? 就是能干的La.last。 无论做过多少次的插入和删除,只要在变化范围内,La.last都能很准确的告诉我们表中的元素有几个。 原因是我们曾经说过,La.last等于当前顺序表的实际表长减去1,即表长等于La.last+1。 intListLength(SeqListL) { returnL.last+1; } 7.定位Locate(L,e)。 所谓的定位就是从首元开始,在顺序表中依次查找某个指定的元素是否存在。 若存在返回所在的位置,否则返回-1。 intLocate(SeqListL,Elemtypee) { inti=0; while() { if()return(i+1); i++; } return-1; } 实验内容2: 请根据上面描述的定位算法思想,补充完整定位算法Locate(L,e),并在实验1的主函数中调用该算法Locate(L,'c')。 8.插入元素InsList(L,i,e)。 在顺序表La的第i个位置上插入一个新元素e。 请注意插入位置i的有效性。 如果顺序表的长度为n,则有(n+1)个位置可以插入元素,即1≦i≦n+1。 当插入位置i=1,即是在表头插入元素。 当插入位置i=n+1,则表示在表尾插入元素。 我们先解决如何在顺序表的尾部插入一个元素e? 若在尾部插入元素,首先要看一下还有没有地方插入元素了,也就是先去判断表是否是满表(还记得如何去判定满表吗? ) 简答: 如果表不满,那么表尾对应的位置i等于多少? a)MAXSIZEb)La.lastc)La.last+1d)顺序表最后一个元素后面的任意位置 答案: c。 (回答一下其他的几个选项为什么不对? ) 接下来讨论插入新元素e如何进行? 请注意了,在顺序表中插入一个新元素的过程是通过C语言中的一条赋值语句来是实现的。 只需要执行语句: La.elem[La.last+1]=e;即可。 如图2.5所示。 A B C D E e …… 0 1 2 3 4 5 …… MAXZISE-1 La.elem La.last插入位置: La.last+1 图2.5在表尾插入元素e的位置 插入步骤完成后,有一件事情非常非常重要,经常会遗忘,你想起来了吗? 对了,要改变La.last的值,因表尾位置已经发生了改变了,要执行La.last++。 插入后的状态应该如图2.6所示。 A B C D E e …… 0 1 2 3 4 5 …… MAXZISE-1 La.elem: La.last 图2.6表尾插入元素e 实验内容3: 请同学们完成这样一个题目: 编程实现在当前的顺序表的尾部连续插入m(m≧1)个元素的过程,被插入的元素由键盘输入。 输出插入前和插入后的顺序表,并回答下述问题: 若有一个顺序表La,最多能够存储MAXSIZE个数据元素,且La。 Last=n(n 通过上面的问题得知,当插入位置在表的尾部的时候,我们要完成插入操作要做这么几件事情: 1)判断是否可以插入(表满判断); 2)落实插入位置(表尾位置为La.last+1); 3)执行插入操作(赋值语句); 4)表长增加(La.last++)。 当插入位置不在表尾的时候,插入过程与插入在表尾是否有区别呢? 下图是在顺序表的第3个位置上插入新元素e的实例描述: 插入前: A B C D E …… 0 1 2 3 4 5 …… MAXZISE-1 La.elem: 移动元素 插入位置i=3表尾La.last=4 插入后: A B e C D E …… 0 1 2 3 4 5 …… MAXZISE-1 La.elem: 插入元素 表尾La.last=5 图2.7插入过程 根据图7所示的插入过程,易得插入步骤如下: 1)判断是否可以插入(表满判断); 2)落实插入位置(要考虑插入位置i的合法性); 3)腾出插入空间(考虑插入位置对应的数组下标并通过移动元素实现腾位子的过程,注意移动的顺序); 4)执行插入操作; 5)表长增加。 根据上述的描述,在顺序表的位置i插入元素e的算法描述如下: #defineOK1 #defineERROR0 intInsList(SeqList*L,inti,Elemtypee) //在顺序表的第i个位置插入元素e { intk; //表满判断 if(L->last>=MAXSIZE-1) { printf("表已满无法插入"); return(ERROR); } //插入位置的合法性判断 if(插入位置不合法) { printf("插入位置i不合法"); return(ERROR); } //腾位置 从后向前依次移位,将要插入元素位置腾出 //插入元素 L->elem[i-1]=e; //表长增加 L->last++; return(OK); } 9.删除元素DelList(L,i,e)。 删除顺序表的第i个元素,并且让e带回被删除元素。 与插入类似,我们先讨论一下删除位置i。 若顺序表La的表长为n,则有n个位置的元素可以删除,即1≦i≦n。 如果n==0,即表为空,则没有合理删除位置了。 先讨论删除表尾元素的过程。 让我们先看示意图2.8: 删除前: A B C D E F …… 0 1 2 3 4 5 …… MAXZISE-1 La.elem La.last==5 删除后: A B C D E F …… 0 1 2 3 4 5 …… MAXZISE-1 La.elem La.last==4 图2.8删除表尾元素 事实上,被删除的表尾元素并没有真正的从顺表La的数组分量La.elem中消失,前面我们曾经说过不论La的数组分量中有多少元素,“有效元”只在La.elem[0]~La.[La.last]中。 所以在删除表尾元素的时候,我们并没有将该元素从数组中清除掉,而是做了一个很简单的操作: La.last--,即将表尾位置向前移动,这样,表中的有效元素就少了一个了。 这一点非常重要,请同学们好好理会。 我们整理删除表尾元素步骤如下: 1)判定是否可以删除(表空判断); 2)落实删除位置的合法性; 3)表长减少1。 编程实现删除当前表尾元素。 接下来让我们讨论删除第i个位置上的元素的算法。 与插入算法类似,删除第i的位置上的元素就是删除元素La.elem[i-1],那么是不是与删除表尾元素一样,只要执行La.last--就可以了呢? 但删除的元素不是表尾元素的时候,删除前和删除后的状态如图2.9所示: 删除前: A B C D E F …… 0 1 2 移动元素 3 4 5 …… MAXZISE-1 La.elem La.last==5 删除第3个元素后: A B D E F F …… 0 1 2 3 4 5 …… MAXZISE-1 La.elem La..last==4 图2.9删除第3个元素 与图2.8相比发现了什么不同了吗? 当删除的元素不是表尾元素的时候,我们是通过元素的移动来覆盖被删除的元素。 能不能够不执行元素的移动,而是通过强制的将该元素变为无效元来完成删除呢? 请同学们一起来讨论一下这个问题吧! 最后,删除了一个元素,表长肯定要减少的,因此删除顺序表的第i个元素的步骤为: 1)表空判断; 2)删除位置合法性判断; 3)移动元素,覆盖被删除元素,移动范围(La.elem[i]~La.elem[La.last]); 4)表长减1; 这样做我们似乎确实实现了顺序表的表尾元素删除,但是很多时候,我们需要的可能不仅仅是这个结果,我们想看一看被删除的元素,就是说我们希望在删除算法中被删除的元素能够被带回,如何带回呢? 。 这里需要一个小小的技巧,就是利用C语言
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 实验 指导 手册
![提示](https://static.bdocx.com/images/bang_tan.gif)