数据结构课程实验报告18.docx
《数据结构课程实验报告18.docx》由会员分享,可在线阅读,更多相关《数据结构课程实验报告18.docx(53页珍藏版)》请在冰豆网上搜索。
![数据结构课程实验报告18.docx](https://file1.bdocx.com/fileroot1/2023-1/25/595dfc80-272d-4ede-b3c3-eb2730ac9575/595dfc80-272d-4ede-b3c3-eb2730ac95751.gif)
数据结构课程实验报告18
课程实验报告
课程名称:
数据结构
专业班级:
信息安全1302班
学号:
U201315151
姓名:
范岩松
指导教师:
周时阳
报告日期:
2015年5月10号
计算机科学与技术学院
1课程实验概述
《数据结构》是计算机程序设计的重要理论技术基础,它不仅是计算机学科的核心课程,而且是已成为其他理工专业的热门选修课。
课程中介绍软件设计中常用的数据结构及其在计算机中的存储结构和操作实现:
线性表、串、栈、队列、数组、树和二叉树、图和文件等。
本次实验分为三部分组成:
1.基于顺序表存储结构的线性表实现
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据结构。
其特点是,为表中相邻的元素
和
赋以相邻的存储位置
和
。
换言之,以元素在计算机内“物理位置相邻”来表示线性表中数据元素之间的逻辑关系。
每一个数据元素的存储位置都和在线性表的起始位置相差一个和数据元素在线性表中的位序成正比的常数。
由此,只要确定了存储线性表的起始位置,线性表中的任一数据元素都可以随机存取,所以线性表的顺序存储结构是一种随机存取的存储结构。
实验实现其数据结构的基本操作:
顺序表的构造、插入、删除、遍历等基本操作。
2.基于链式存储结构的线性表实现
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。
因此为了表示每个数据元素
与其直接后继数据元素
之间的逻辑关系,对数据元素
来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。
这两部分信息组成数据元素
的存储映像。
实验实现其数据结构的基本操作:
链式表的构造、插入、删除、遍历等基本操作。
3.基于二叉链表的二叉树实现
二叉树是一种树型结构,其特点是每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点),并且,二叉树的子树有左右之分,其次序不能任意颠倒。
由二叉树定义知,二叉树的结点由一个数据元素和分别指向其左、右子树的两个分支构成,则表示二叉树的链式表中的结点至少包含3个域:
数据域和左、右指针域。
实验实现其基本数据结构的基本操作:
二叉树的构造、插入、删除、前序遍历、中序遍历、后序遍历等基本操作。
2实验一基于顺序结构的线性表实现
2.1问题描述
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。
假设线性表的每个元素需占用
个存储单元,并已所占的第一个单元的存储地址作为数据元素的存储位置。
则线性表中第
个数据元素的存储位置
和第
个数据元素的存储位置
之间满足下列关系:
一般来说,线性表的第
个元素
的存储位置为
式中
是线性表的第一个数据元素
的存储位置,通常称做线性表的起始位置或者基地址。
2.2系统设计
本次实验主要是设计实现以下顺序表的基本操作:
1.构造一个空顺序表、2.销毁顺序表、3.将一个顺序表置空、4.判断一个顺序表是否为空、5.返回顺序表中的数据元素个数、6.返回顺序表中第
个数据元素、7.返回顺序表中第1个与所输入元素相同的顺序表中的元素位序、8.返回顺序表中的某个元素的前驱元素,若无前驱操作失败、9.返回顺序表中的某个元素的后继元素,若无后继操作失败、10.在顺序表第
个位置之前插入新的元素、11.删除顺序表中的第
个元素、12.遍历整个顺序表。
在对顺序表的定义了解熟悉后,并分析实现各个基本操作的算法。
采用动态分配的方法构造线性顺序表,如下所示:
#defineLIST_INIT_SIZE100
#defineLISTINCREMENT10
typedefstruct
{ElemType*elem;//存储空间基地址
intlength;//表长
intlistsize;//当前分配的存储容量
//(以sizeof(ElemType)为单位
}SqList;
SqListLb;
其中:
typedef---别名定义,SqList----结构类型名
Lb----结构类型变量名
Lb.length---表长
Lb.elem[0]----a1
Lb.elem[Lb.length-1]---an
以此结构编写代码实现各个基本操作的函数。
1.构造一个空顺序表:
statusIntiaList(SqList&L)
{
L.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!
L.elem)exit(OVERFLOW);
L.length=0;
L.listsize=LIST_INIT_SIZE;
returnOK;
}
2.销毁顺序表:
statusDestroyList(SqList&L)
{
if(L.elem!
=NULL)
{
L.length=0;
L.length=0;
free(L.elem);
}
returnOK;
}
3.将一个顺序表置空:
statusClearList(SqList&L)
{
L.length=0;
returnOK;
}
4.判断一个顺序表是否为空:
statusListEmpty(SqListL)
{
if(L.length==0)
returnTRUE;
else
returnFALSE;
}
5.返回顺序表中的数据元素个数:
intListLength(SqListL)
{
if(L.elem!
=NULL)
returnL.length;
elsereturnERROR;
}
6.返回顺序表中第
个数据元素:
首先判断所输入的i值符合条件,其次再返回顺序表中的第i个元素,要注意在数组中以0开始,则第i个元素的数组下标是i-1。
statusGetElem(SqListL,inti,ElemType&e)
{
if(i<1||i>L.length)
returnERROR;
else
{
e=L.elem[i-1];
returnOK;
}
}
7.返回顺序表中第1个与所输入元素相同的顺序表中的元素位序:
首先判断数组是否为空,若不为空,则遍历整个顺序表与输入的元素一一进行判断,再返回其值。
statusLocateElem(SqListL,ElemTypee)
{
if(L.elem!
=NULL)
{
for(inti=0;i{
if(e==L.elem[i])
returni+1;
}
}
returnERROR;
}
8.返回顺序表中的某个元素的前驱元素:
首先判断所输入的元素是否为第一个元素,若不是,再进行遍历,当判断发现符合条件的元素时,返回其前驱元素,同样在这里要注意数组的下标。
statusPriorElem(SqListL,ElemTypecur,ElemType&pre_e)
{
inti=2;
if(cur==L.elem[0])returnERROR;
while(i<=L.length&&L.elem[i-1]!
=cur)
i++;
if(i==L.length+1)returnERROR;
elsepre_e=L.elem[i-2];
returnOK;
}
9.返回顺序表中的某个元素的后继元素,若无后继操作失败:
首先判断所输入的元素是否为最后一个个元素,若不是,再进行遍历,当判断发现符合条件的元素时,返回其后继元素,同样在这里要注意数组的下标。
statusNextElem(SqListL,ElemTypecur,ElemType&next_e)
{
inti=1;
while(i<=L.length&&L.elem[i-1]!
=cur)
i++;
if(i==L.length)returnERROR;
elsenext_e=L.elem[i];
returnOK;
}
10.在顺序表第
个位置之前插入新的元素:
首先判断所插入的位置是否符合条件,其次在判断所输入的长度是否超出分配空间,如若超出,则分配新的空间。
再进行插入操作。
statusListInsert(SqList&L,inti,ElemTypee)
{
ElemType*newbase,*q,*p;
if(i<1||i>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[i-1]);
for(p=&(L.elem[L.length-1]);p>=q;--p)*(p+1)=*p;
*q=e;
++L.length;
returnOK;
}
11.删除详顺序表中的第
个元素:
首先判断所插入的位置是否符合条件,其次再将所要删除的元素赋值为其后的元素,将顺序表长度缩减。
statusListDelete(SqList&L,inti,ElemType&e)
{
intj;
if((i<1)||(i>L.length))returnERROR;
for(j=i;j<=L.length-1;j++)
L.elem[j-1]=L.elem[j];
--L.length;
returnOK;
}
12.遍历整个顺序表:
statusListTrabverse(SqListL)
{
inti;
printf("\n--------------------allelements------------------------------\n");
for(i=0;iprintf("\n-------------------------end----------------------------------\n");
returnL.length;
}
以上为线性顺序表的12个基本操作的函数调用。
2.3系统实现
1.构造一个空顺序表
2.销毁顺序表
3.将一个顺序表置空
4.判断一个顺序表是否为空
构造一个非空线性表101267843
5.返回顺序表中的数据元素个数
由4知顺序表为10126784
则总共有7个元素
6.返回顺序表中第
个数据元素
由4所构造线性表返回第四个元素应为7
7.返回顺序表中第1个与所输入元素相同的顺序表中的元素位序
由4所得线性表知输入4,则返回其元素所在位序为6
8.返回顺序表中的某个元素的前驱元素,若无前驱操作失败
由4所构造顺序表,若输入7,则返回其前驱为6
若输入第一个元素10则其无前驱元素
9.返回顺序表中的某个元素的后继元素,若无后继操作失败
由4所构造顺序表若输入8,则返回其后继元素4
若输入顺序表中国最后一个元素3,则其无后继元素
10.在顺序表第
个位置之前插入新的元素
在位序为5的位置插入元素14
11.删除顺序表中的第
个元素
由4所构造的线性表删除第三个元素6
删除之前:
删除之后:
12.遍历整个顺序表
如构造顺序表12345678
2.4效率分析
线性顺序表顺序表一般表现为数组,使用一组地址连续的存储单元依次存储数据元素,如图1所示。
它具有如下特点:
长度固定,必须在分配内存之前确定数组的长度。
存储空间连续,即允许元素的随机访问。
存储密度大,内存中存储的全部是数据元素。
要访问特定元素,可以使用索引访问,时间复杂度为 O
(1)。
要想在顺序表中插入或删除一个元素,都涉及到之后所有元素的移动,因此时间复杂度为 O(n)。
顺序表最主要的问题就是要求长度是固定的,可以使用倍增-复制的办法来支持动态扩容,将顺序表变成“可变长度”的。
具体做法是初始情况使用一个初始容量(可以指定)的数组,当元素个数超过数组的长度时,就重新申请一个长度为原先二倍的数组,并将旧的数据复制过去,这样就可以有新的空间来存放元素了。
这样,列表看起来就是可变长度的。
这个办法不可避免的会浪费一些内存,因为数组的容量总是倍增的。
而且每次扩容的时候,都需要将旧的数据全部复制一份,肯定会影响效率。
不过实际上,这样做还是直接使用链表的效率要高。
线性表顺序存储的优缺点:
1.优点:
(1)是一种随机存取结构,存取任何元素的时间是一个
常数,速度快;
(2)结构简单,逻辑上相邻的元素在物理上也是相邻的;
(3)不使用指针,节省存储空间。
2.缺点:
(1)插入和删除元素要移动大量元素,消耗大量时间;
(2)需要一个连续的存储空间;
(3)插入元素可能发生“溢出”;
(4)自由区中的存储空间不能被其它数据占用(共享)。
3实验二基于链式结构的线性表实现
3.1问题描述
虽然线性顺序表可以随机存取表中任一元素,它的的存储位置可以用一个简单、直观的公式来表示。
然而,从另一方面来看,在作插入或删除操作时,需移动大量元素。
而链式存储结构则没有顺序存储结构的缺点。
线性表的链式存储结构是用一组任意的存储单元存储线性表中的数据元素。
用线性链表表示线性表时,数据元之间的逻辑关系是由结点中的指针指示的。
话句话说,指针为数据元素之间的逻辑关系的映像,则逻辑上相邻的两个数据元素其存储的物理位置不要求相邻。
在此,以单链表为例,简要介绍链式存储结构的形式:
不带表头结点的单链表:
datanext
head
---→
a1
---→
a2
..-→
an
^
头指针首结点尾结点
带表头结点的单链表:
a.非空表:
datanext
head
---→
///
--→
a1
--→
..--→
an
^
头指针表头结点首结点尾结点
b.空表:
datanext
head
---→
///
^
头指针表头结点
其中:
data称为数据域,next称为指针域/链域
当head==NULL,为空表;否则为非空表。
3.2系统设计
在对链式表的定义了解熟悉后,并分析实现各个基本操作的算法。
采用动态分配的方法构造线性链式表,如下所示:
用typedef定义指针类型:
typedefstructLnode
{ElemTypedata;//data为抽象元素类型
structLnode*next;//next为指针类型
}Lnode,*Linklist;
指针变量head,p,q的说明:
Linklisthead,p,q;等同于Lnode*head,*p,*q;
以此结构体为基础来进行链式表的基本操作实现。
本次实验主要是设计实现以下链式表的基本操作:
1.构造一个空链式表、2.销毁链式表、3.将一个链式表置空、4.判断一个链式表是否为空、5.返回链式表中的数据元素个数、6.返回链式表中第
个数据元素、7.返回链式表中第1个与所输入元素相同的链式表中的元素位序、8.返回链式表中的某个元素的前驱元素,若无前驱操作失败、9.返回链式表中的某个元素的后继元素,若无后继操作失败、10.在链式表第
个位置之前插入新的元素、11.删除链式表中的第
个元素、12.遍历整个链式表。
1.构造一个空链式表
statusIntiaList(LinkList&L)
{
L=(LinkList)malloc(sizeof(LNode));
if(!
L)exit(OVERFLOW);
L->next=NULL;
returnOK;
}
2.销毁链式表
statusDestroyList(LinkList&L)
{
LinkListq;
while(L)
{
q=L->next;
free(L);
L=q;
}
returnOK;
}
3.将一个链式表置空
statusClearList(LinkList&L)
{
LinkListp,q;
p=L->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
L->next=NULL;
returnOK;
}
4.判断一个链式表是否为空
statusListEmpty(LinkListL)
{
if(L->next)
returnFALSE;
elsereturnTRUE;
}
5.返回链式表中的数据元素个数
首先定义一个指针指向首指针,当其不为空时,循环操作,继续让其指向下一个指针,当为空时,返回其循环次数即为链式表的数据元素个数。
intListLength(LinkListL)
{
inti=0;
LinkListp=L->next;
while(p)
{
i++;
p=p->next;
}
returni;
}
6.返回链式表中第
个数据元素
首先定义一个指针指向首指针,当其不为空时,进行循环操作。
当找到元素时赋值返回。
statusGetElem(LinkListL,inti,ElemType&e)
{
LinkListp;
intj=1;
p=L->next;
while(p&&j
{
p=p->next;
++j;
}
if(!
p||j>i)
returnERROR;
e=p->data;
returnOK;
}
7.返回链式表中第1个与所输入元素相同的链式表中的元素位序
首先定义一个指针指向头结点,当该结点不为空时,循环操作判断输入元素是否与结点元素相同,若相同则进行返回。
statusLocateElem(LinkListL,ElemTypee)
{
inti=0;
LinkListp=L->next;
while(p)
{
++i;
if(e==p->data)
returni;
p=p->next;
}
returnERROR;
}.
8.返回链式表中的某个元素的前驱元素,若无前驱操作失败
首先设置两个指针,一个指向头结点,另一个指向头结点的下一个结点,循环操作判断其结点的下一个结点是否与你输入的值相同,判断成功,则返回当前结点的值。
statusPriorElem(LinkListL,ElemTypecur,ElemType&pre_e)
{
LinkListp,q;
p=L->next;
while(p->next)
{
q=p->next;
if(q->data==cur)
{
pre_e=p->data;
returnOK;
}
p=q;
}
returnERROR;
}
9.返回链式表中的某个元素的后继元素,若无后继操作失败
statusNextElem(LinkListL,ElemTypecur,ElemType&next_e)
{
LinkListp=L->next;
while(p->next)
{
if(p->data==cur)
{
next_e=p->next->data;
returnOK;
}
p=p->next;
}
returnERROR;
}
10.在链式表第
个位置之前插入新的元素
statusListInsert(LinkList&L,inti,ElemTypee)
{
LinkListp=L,q;
intj=0;
while(p&&j{
p=p->next;
j++;
}
if(!
p||j>i-1)
returnERROR;
q=(LinkList)malloc(sizeof(LNode));
q->data=e;
q->next=p->next;
p->next=q;
returnOK;
}
11.删除链式表中的第
个元素
statusListDelete(LinkList&L,inti,ElemType&e)
{
LinkListp=L,q;
intj=0;
while(p->next&&j{
p=p->next;
++j;
}
if(!
(p->next)||j>i-1)
returnERROR;
q=p->next;
p->next=p->next->next;
e=q->data;
free(q);
returnOK;
}
12.遍历整个链式表
statusListTrabverse(LinkListL)
{
printf("\n--------------------allelements------------------------------\n");
LinkListp=L->next;
while(p)
{
printf("%d",p->data);
p=p->next;
}
printf("\n-------------------------end----------------------------------\n");
returnOK;
}
3.3系统实现
1.构造一个空链式表
2.销毁链式表
3.将一个链式表置空
首先构造一个非空链表1234
将其置为空
4.判断一个链式表是否为空
首先构造一个非空链表
再次判断其是否为空
5.返回链式表中的数据元素个
如图构造一个线性链表23967
则元素个数应为五个
6.返回链式表中第
个数据元素
构造线性链式表23967
则返回第五个元素的值应为7
7.返回链式表中第1个与所输入元素相同的链式表中的元素位序
构造线性链表23967
则返回链式表的第三个元素应为9
8.返回链式表中的某个元素的前驱元素,若无前驱操作失败
同上构造线性链式表23967
若输入元素6,则应该返回其前驱元素9
若输