数据结构实验指导书02.docx

上传人:b****3 文档编号:3750708 上传时间:2022-11-25 格式:DOCX 页数:29 大小:87.13KB
下载 相关 举报
数据结构实验指导书02.docx_第1页
第1页 / 共29页
数据结构实验指导书02.docx_第2页
第2页 / 共29页
数据结构实验指导书02.docx_第3页
第3页 / 共29页
数据结构实验指导书02.docx_第4页
第4页 / 共29页
数据结构实验指导书02.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

数据结构实验指导书02.docx

《数据结构实验指导书02.docx》由会员分享,可在线阅读,更多相关《数据结构实验指导书02.docx(29页珍藏版)》请在冰豆网上搜索。

数据结构实验指导书02.docx

数据结构实验指导书02

实验二线性表

2.1实验目的:

(1)掌握线性表的顺序存储结构的定义及C语言实现。

(2)掌握线性表在顺序存储结构即顺序表中的各种基本操作。

(3)掌握线性表的链式存储结构——单链表的定义及C语言实现。

(4)掌握线性表在链式存储结构——单链表中的各种基本操作。

2.2实验要求:

(1)复习课本中有关线性表的知识;

(2)用C语言完成算法和程序设计并上机调试通过;

(3)撰写实验报告,给出算法思路或流程图和具体实现(源程序)、算法分析结果(包括时间复杂度、空间复杂度以及算法优化设想)、输入数据及程序运行结果(必要时给出多种可能的输入数据和运行结果)。

2.3基础实验

[实验1]顺序表的建立

实验内容与要求:

建立一个含n个数据元素的顺序表并输出该表中各元素的值及顺序表的长度。

分析:

顺序表是线性表的顺序存储结构,是指用一组连续的内存单元依次存放线性表的数据元素。

在顺序存储结构下,逻辑关系相邻的两个元素在物理位置上也相邻,这是顺序表的特点。

若一个数据元素仅占一个存储单元,则其存储方式参图2-1。

 

 

从图中可见,第i个数据元素的地址为:

Loc(ai)=loc(a1)+(i-1)

假设线性表中每个数据元素占用l个存储单元,那么在顺序表中,线性表的第i个元素的存储位置与第1个元素的存储位置的关系是:

Loc(ai)=Loc(a1)+(i–1)l

这里Loc(ai)是第i个元素的存储位置,Loc(a1)是第1个元素的存储位置,也称为线性表的基址;显然,顺序表便于进行随机访问,故线性表的顺序存储结构即顺序表是一种随机存储的结构。

由于C语言的数组类型也有随机存取的特点,一维数组的机内表示就是顺序结构。

因此,可用C语言的一维数组实现线性表的顺序存储。

因此利用C语言的结构体类型定义顺序表:

#defineLIST_INIT_SIZE100

#defineLISTINCREMENT10

typedefintElemType;//线性表中存放整型元素(将抽象数据类型ElemType

typedefstruct//具体化int类型

{

ElemType*elem;//存储空间首地址

intlength;//线性表的当前长度

intlistsize;//当前分配的存储单元数,(以sizeof(ElemType)为单位)

}SqList;

将此结构定义放在一个头文件SqList.h里,可避免在后面的参考程序中代码重复书写,另外在该头文件里给出顺序表的初始化及常量的定义。

参考程序:

//头文件SqList.h的内容如下:

#include

#include

#defineLIST_INIT_SIZE100

#defineLISTINCREMENT10

#defineTRUE1

#defineFALSE0

#defineOK1

#defineERROR0

#defineINFEASIBLE-1

#defineOVERFLOW-2

typedefintElemType;

typedefintStatus;

typedefstruct{

ElemType*elem;

intlength;

intlistsize;

}SqList;

StatusInitList_Sq(SqList*L)

{

L->elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));

if(!

L->elem)return(OVERFLOW);

L->length=0;

L->listsize=LIST_INIT_SIZE;

returnOK;

}

StatusCreatList_Sq(SqList*L,intn)

{

inti;

printf("输入%d个整数:

\n",n);

for(i=0;i

scanf("\n%d",&L->elem[i]);

returnOK;

}

//以下是整个源程序(保存在shiyan2_1_1.c文件中):

#include

#include"SqList.h"

voidmain()

{

inti,n;

SqLista;

SqList*l=&a;

if(InitList_Sq(l)=-2)printf("分配失败\n");

printf("\n输入要建立的线性表l的长度n:

");//输入线性表的长度

scanf("%d",&n);

l->length=n;

printf("线性表的长度是:

%d\n",l->length);

CreatList_Sq(l,n);//生成线性表

printf("输出线性表l中的元素值:

");//输出线性表中的元素

for(i=0;ilength;i++)

printf("%7d",l->elem[i]);

getch();

}

[实验2]顺序表的插入

实验内容与要求:

利用前面的实验先建立一个顺序表L={21,23,14,5,56,17,31},然后在第i个位置插入元素68,通过对比插入元素前后的线性表发生的变化,判断插入操作是否正确。

分析:

从插入位置到最后位置的所有元素都要后移一位,使空出的位置插入元素值e。

一般在第i个元素之前(1<=i<=n)插入一个新元素时,需要有n-i+1个元素进行移动。

但是,插入的位置是不固定的,当插入位置i=1时,全部元素都得移动,需n次移动,当i=2时,移动n-1个元素,依次类似,当i=n时,仅需移动元素一次。

如图2-2所示。

注意如何取到第i个元素,在插入过程中注意溢出情况以及数组的下标与位序(顺序表中元素的次序)的区别。

 

 

参考程序:

//保存在shiyan2_1_2.c文件中

#include

#include

#include"SqList.h"

StatusListInsert_Sq(SqList*L,inti,ElemTypee){

//在线性表L中的第i个位置前插入一个值为e的元素

//i的取值范围:

1<=i<=ListLength_Sq(L)

ElemType*newbase,*q,*p;

if(i<1||i>L->length+1)returnERROR;//i值不合法

if(L->length>=L->listsize){//当前存储空间已满,增加分配量

newbase=(ElemType*)realloc(L->elem,

(L->listsize+LISTINCREMENT)*sizeof(ElemType));

if(!

newbase)return(OVERFLOW);//存储分配失败

L->elem=newbase;//新基址

L->length=+LISTINCREMENT;//增加存储容量

}//if

q=&(L->elem[i-1]);//q为插入位置

for(p=&(L->elem[L->length-1]);p>=q;--p)*(p+1)=*p;

//插入位置及以后的元素右移

*q=e;//插入e

++L->length;//表长增1

returnOK;

}//ListInsert_Sq

voidmain()

{

intn,i,x;

SqList*L,a;

L=&a;

InitList_Sq(L);

printf("\n输入要建立的线性表L的长度:

");

scanf("%d",&n);

L->length=n;

CreatList_Sq(L,n);

printf("\n插入元素之前线性表L的长度是:

%d",L->length);

printf("\n插入元素之前线性表L中的元素是:

");

for(i=0;ilength;i++)

printf("%5d",L->elem[i]);

printf("\n输入要插入元素的位置:

");

scanf("%d",&i);

printf("\n输入要插入的元素的值:

");

scanf("\n%d",&x);

if(ListInsert_Sq(L,i,x)>0)

{

printf("\n插入元素之后线性表L的长度是:

%d",L->length);

printf("\n插入元素之后线性表L的元素是:

\n");

for(i=0;ilength;i++)

printf("%5d",L->elem[i]);

}//if

else

printf("can'tinsertthedata!

\n");

getch();

}

[实验3]单链表的建立

实验内容与要求:

建立一个带头结点的单链表,结点的值域为整型数据。

要求将用户输入的数据按尾插入法来建立相应单链表。

分析:

为了便于实现各种运算,通常在单链表的第一个结点前增设一个附加结点,称为头结点,它的结构与表结点相同,其数据域可不存储信息,也可存储表长等附加信息,具体见图2_3。

(a)不带头结点

 

 

 

(b)带头结点的单链表

 

 

单链表的结点结构除数据域外,还含有一个指针域。

用C语言描述结点结构如下:

typedefintElemType;

typedefstructLNode

{

ElemTypedata;//数据域

structLNode*next;//指针域

}Lnode,*Linklist;

注意结点的建立方法及构造新结点时指针的变化。

构造一个结点需用到C语言的标准函数malloc(),如给指针变量p分配一个结点的地址:

p=(Linklist)malloc(sizeof(LNode));该语句的功能是申请分配一个LNode类型结点的地址空间,并将首地址存入指针变量p中。

当结点不需要时可以用标准函数free(p)释放结点存储空间,这时p为空值(NULL)。

参考程序:

//保存在头文件LinkList.h

#include

#include

#defineNULL0

typedefintElemType;

typedefstructLNode{

ElemTypedata;

structLNode*next;

}LNode,*LinkList;

voidCreatList_L(LinkListL,intn)

{

inti;

LinkListp,q;

q=L;

for(i=1;i<=n;i++)

{

p=(LinkList)malloc(sizeof(LNode));

printf("输入线性表的第%d个元素:

",i);

scanf("%d",&p->data);

p->next=q->next;

q->next=p;

q=q->next;

}

}

//以下程序保存在文件shiyan2_1_3.c中:

#include"LinkList.h"

voidmain()

{

LinkListhead,p;

intn;

printf("\n输入要建立链表的长度:

");

scanf("%d",&n);

head=(LinkList)malloc(sizeof(LNode));

head->next=NULL;

CreatList_L(head,n);

printf("\n以head为头指针的链表中的元素:

");

p=head->next;

while(p)

{

printf("%5d",p->data);

p=p->next;

}

getch();

}

[实验4]单链表的合并

实验内容与要求:

建立两个带头结点的有序单链表La,Lb(单调递增),利用La,Lb的结点空间,将La和Lb合并成一个按元素值递增的有序单链表Lc。

分析:

对于单链表的操作必须清楚如何将结点插入到链表中,比如将新结点x插入到结点a和b之间,插入结点的指针变化如图2-4所示。

 

 

 

 

 

程序需要3个指针:

pa,pb,pc,其中pa,pb分别指向La表、Lb表的首结点,用pa遍历La表,pb遍历Lb表,pc指向合并后的新表的最后一个结点(即尾结点),pc的初值指向La表的头结点。

合并的思想是:

先利用实验3的内容建立好两个链表La表和Lb表,然后依次扫描La和Lb中的元素,比较当前元素的值,将较小者链到*pc之后,如此重复直到La或Lb结束为止,再将另一个链表余下的内容链到pc所指的结点之后。

参考程序:

//以下是程序保存在shiyan2_1_4.c文件中

#include"LinkList.h"

voidMergeList_L(LinkListLa,LinkListLb,LinkListLc)

{

LinkListpa,pb,pc;

pa=La->next;

pb=Lb->next;

pc=Lc;

while(pa&&pb)

{

if(pa->data>pb->data)

{

pc->next=pb;

pc=pb;

pb=pb->next;

}

else

{

pc->next=pa;

pc=pa;

pa=pa->next;

}

}

pc->next=pa?

pa:

pb;

free(Lb);

}

voidmain()

{

LinkListLa,Lb,Lc,p;

intn1,n2;

La=(LinkList)malloc(sizeof(LNode));

La->next=NULL;

Lb=(LinkList)malloc(sizeof(LNode));

Lb->next=NULL;

Lc=NULL;

printf("\n请输入要建立的链表La的长度:

");

scanf("%d",&n1);

CreatList_L(La,n1);

printf("\n请输入要建立的链表Lb的长度");

scanf("%d",&n2);

CreatList_L(Lb,n2);

p=La->next;

printf("\n链表La中的元素:

");

while(p)

{

printf("%5d",p->data);

p=p->next;

}

p=Lb->next;

printf("\n链表Lb中的元素:

");

while(p)

{

printf("%5d",p->data);

p=p->next;

}

MergeList_L(La,Lb,Lc);

p=Lc->next;

printf("\n输出由链表La和Lb归并得到的链表Lc中的元素:

\n");

while(p)

{

printf("%d",p->data);

p=p->next;

}

getch();

}

[实验5]删除单链表中的重复值

实验内容与要求:

编写算法实现将单链表L中值重复的结点删除,使所得结果表中各结点值均不相同。

分析:

本题涉及到单链表中关于值的查找算法,从头结点开始,活动指针p沿着单链表向后扫描,寻找某个给定值。

首先建立一个单链表,令p指针指向所建单链表的第一个结点,令q指向p的后继结点,q沿着链表向右(向后)扫描,若找到与p所指结点值相同的结点,则将其删除,继续处理,直到q为空;然后令p移到下一个结点(即直接后继结点),q依然指向p的后继结点,重复同样的处理。

显然此题需要用到双重循环。

参考程序:

//以下程序保存在shiyan2_1_5.c

#include"LinkList.h"

//DeleteSameNode函数用来删除链表中重复的结点

voidDeleteSameNode(LinkListh)

{

LinkListp,q,s

 p=h->next;

 s=p;

 while(p!

=NULL)

{

q=p->next;

 while(q!

=NULL)

{

if(q->data!

=p->data)

{

s=q;//s为q的直接前趋指针,即s紧跟着q向右移动。

q=q->next;

}//if

else

{

s->next=q->next;//此时q所指向的结点为待删除结点

 free(q);

 q=s->next;//q指向后继结点,继续寻找与p所指结点值相同的结点。

 }//else

 }//while(q!

=NULL)

 p=p->next;

s=p;

}//while(p!

=NULL)

}

 //OutPut函数用来输出单链表的内容

voidOutPut(LinkListh)

{

LinkListp;

p=h->next;

while(p)

{

printf("%5",p->data);

p=p->next;

}//while

}

voidmain()

{

LinkListhead;

intn;

head=(LinkList)malloc(sizeof(LNode));

head->next=NULL;

printf("请输入要建立的链表的长度:

\n");

scanf("%d",&n);

CreatList(head,n);

printf("链表中的元素是:

\n");

output(head);

printf("删除链表中结点的重复值!

\n");

DeleteSameNode(head);

OutPut(head);//输出经过处理后的单链表,此时单链表中的值应该唯一。

}

[实验6]单循环链表的逆置

实验内容与要求:

将一个已知的单循环链表进行逆置运算,如(a1,a2,a3,…,an)变为(an,an-1,…,a2,a1)。

分析:

对于单链表而言,最后一个结点的指针域是空指针,如果将该链表头指针置入该指针域,则使得链表头尾结点相连,就构成了单循环链表。

对于单链表只能从头结点开始遍历整个链表,而对于单循环链表则可以从表中任意结点开始遍历整个链表。

所谓链表的逆置运算(或称为逆转运算)是指在不增加新结点的前提下,依次改变数据元素的逻辑关系,使得线性表(a1,a2,a3,…,an)成为(an,an-1,…,a2,a1)。

本题采用的算法是:

先建立一个带头结点的单循环链表,从头到尾扫描单链表L,把p作为活动指针,沿着链表向前移动,q作为p前趋结点,r作为q的前趋结点。

其中,q的next值为r,r的初值置为head。

参考程序:

//头文件LNode.h的内容:

#include

#include

#defineNULL0

typedefintElemType;

typedefstructLNode

{

ElemTypedata;//数据域

structLNode*next;//指针域

}LNode,*LinkList;

//以下是主程序保存在shiyan2_1_6.c中

#include“LNode.h”

//输出循环链表的信息

voidOutPut(LinkListhead)

{

LinkListp;

p=head->next;

while(p!

=head)

{

printf("%5d",p->data);

p=p->next;

}//while

}

//建立单循环链表

voidCreat(LinkListh,intn)

{

intk;

LNode*r,*p;

r=h;

for(k=1;k<=n;k++)

{

printf(“输入第%d个结点的数值:

”,k);

p=(LNode*)malloc(sizeof(LNode));

scanf(“%d”,&p->data);

p->next=h;

r->next=p;

r=p;

}

}

//逆置函数

voidInvert(LinkListh)

{

LinkListp,q,r;

p=h->next;

q=h;

while(p!

=h)

{

r=q;

q=p;

p=p->next;

q->next=r;

}

h->next=q;

}

 voidmain()

{

intn;

LinkListhead;

printf("\n输入所建立的循环链表的结点个数:

");

scanf("%d",&n);

head=(LNode*)malloc(sizeof(LNode));

head->next=head;

Creat(head,n);

printf("输出建立的单循环链表:

");

OutPut(head);

printf("\n现在进行逆置!

\n");

Invert(head);

printf("\n输出进行逆置运算后的单循环链表的结点信息:

");

OutPut(head);

}

2.4提高实验

[实验1]学生成绩管理

实验内容与要求:

学生成绩管理是学校教务管理的重要组成部分,其处理信息量很大,本实验是对学生的成绩管理作一个简单的模拟,用菜单选择操作方式完成下列功能:

①登录学生成绩;

②查询学生成绩;

③插入学生成绩;

④删除学生成绩

分析:

本实验涉及单链表的各种操作,包括单链表的建立、结点的查找、插入、删除等基本运算。

链表中插入结点的指针变化见图2-4所示,删除p所指结点的指针变化见图2-5所示。

 

首先建立学生成绩单链表,每条记录由学号、姓名与成绩组成,即链表中每个结点由4个域组成,分别为:

学号、姓名、成绩、存放下一个结点地址的next域。

然后将要求完成的四项功能写成四个函数,登记学生成绩对应建立学生单链表的功能,后三个功能分别对应单链表的查询、插入与删除三大基本操作。

该系统中的数据采用线性表中的链式存储结构即单链表来存储,用结构体类型定义每个学生记录,这样单链表中每个结点的结构可描述为:

#defineMAXLEN100

typedefstructNode

{

intnum;//学号

charname[MAXLEN];//姓名

floatscore;//成绩

structNode*next;

}Node;

参考程序

//头文件hh.h的内容

#include

#include

#include

#defineMAXLEN100

#defineNULL0

typedefstructNode

{

intnum;

charn

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1