编程教学 数据结构实验.docx
《编程教学 数据结构实验.docx》由会员分享,可在线阅读,更多相关《编程教学 数据结构实验.docx(43页珍藏版)》请在冰豆网上搜索。
编程教学数据结构实验
《数据结构》上机实验的目的和要求
通过上机实验加深对课程内容的理解,增加感性认识,提高软件设计、编写及调试程序的能力。
要求所编的程序能正确运行,并提交实验报告。
实验报告的基本要求为:
1、需求分析:
陈述程序设计的任务,强调程序要做什么,明确规定:
(1)输入的形式和输出值的范围;
(2)输出的形式;
(3)程序所能达到的功能;
(4)测试数据:
包括正确的输入输出结果和错误的输入及输出结果。
2、概要设计:
说明用到的数据结构定义、主程序的流程及各程序模块之间的调用关系。
3、详细设计:
提交带注释的源程序或者用伪代码写出每个操作所涉及的算法。
4、调试分析:
(1)调试过程中所遇到的问题及解决方法;
(2)算法的时空分析;
(3)经验与体会。
5、用户使用说明:
说明如何使用你的程序,详细列出每一步操作步骤。
6、测试结果:
列出对于给定的输入所产生的输出结果。
若有可能,测试随输入规模的增长所用算法的实际运行时间的变化。
实验一、单链表的插入和删除
一、目的:
了解和掌握线性表的逻辑结构和链式存储结构,掌握单链表的基本算法及相关的时间性能分析。
二、要求:
建立一个数据域定义为字符串的单链表,在链表中不允许有重复的字符串;根据输入的字符串,先找到相应的结点,后删除之。
三、示例程序:
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"ctype.h"
typedefstructnode//定义结点
{
chardata[10];//结点的数据域为字符串
structnode*next;//结点的指针域
}ListNode;
typedefListNode*LinkList;//自定义LinkList单链表类型
LinkListCreatListR1();//函数,用尾插入法建立带头结点的单链表
ListNode*LocateNode();//函数,按值查找结点
voidDeleteList();//函数,删除指定值的结点
voidprintlist();//函数,打印链表中的所有值
voidDeleteAll();//函数,删除所有结点,释放内存
//==========主函数==============
voidmain()
{
char*ch,*num;
LinkListhead;
head=CreatListR1();//用尾插入法建立单链表,返回头指针
printlist(head);//遍历链表输出其值
printf("Deletenode(y/n):
");//输入“y”或“n”去选择是否删除结点
scanf("%s",num);
if(strcmp(num,"y")==0||strcmp(num,"Y")==0){
printf("PleaseinputDelete_data:
");
scanf("%s",ch);//输入要删除的字符串
DeleteList(head,ch);
printlist(head);
}
DeleteAll(head);//删除所有结点,释放内存
}
//==========用尾插入法建立带头结点的单链表===========
LinkListCreatListR1(void)
{
char*ch;
LinkListhead=(LinkList)malloc(sizeof(ListNode));//生成头结点
ListNode*s,*r,*pp;
r=head;
r->next=NULL;
printf("Input#toend");//输入“#”代表输入结束
printf("PleaseinputNode_data:
");
scanf("%s",ch);//输入各结点的字符串
while(strcmp(ch,"#")!
=0){
pp=LocateNode(head,ch);//按值查找结点,返回结点指针
if(pp==NULL){//没有重复的字符串,插入到链表中
s=(ListNode*)malloc(sizeof(ListNode));
strcpy(s->data,ch);
r->next=s;
r=s;
r->next=NULL;
}
printf("Input#toend");
printf("PleaseinputNode_data:
");
scanf("%s",ch);
}
returnhead;//返回头指针
}
//==========按值查找结点,找到则返回该结点的位置,否则返回NULL==========
ListNode*LocateNode(LinkListhead,char*key)
{
ListNode*p=head->next;//从开始结点比较
while(strcmp(p->data,key)!
=0&&p)//直到p为NULL或p->data为key止
p=p->next;//扫描下一个结点
returnp;//若p=NULL则查找失败,否则p指向找到的值为key的结点
}
//==========删除带头结点的单链表中的指定结点=======
voidDeleteList(LinkListhead,char*key)
{
ListNode*p,*r,*q=head;
p=LocateNode(head,key);//按key值查找结点的
if(p==NULL){//若没有找到结点,退出
printf("positionerror");
exit(0);
}
while(q->next!
=p)//p为要删除的结点,q为p的前结点
q=q->next;
r=q->next;
q->next=r->next;
free(r);//释放结点
}
//===========打印链表=======
voidprintlist(LinkListhead)
{
ListNode*p=head->next;//从开始结点打印
while(p){
printf("%s,",p->data);
p=p->next;
}
printf("\n");
}
//==========删除所有结点,释放空间===========
voidDeleteAll(LinkListhead)
{
ListNode*p=head,*r;
while(p->next){
r=p->next;
free(p);
p=r;
}
free(p);
}
四、实验内容
1、分析、理解程序。
2、调试程序,并设计输入数据(如:
bat,cat,eat,fat,hat,jat,lat,mat,#),测试程序的如下功能:
不允许重复字符串的插入;根据输入的字符串,找到相应的结点并删除。
3、修改程序:
(1) 增加插入结点的功能。
(2) 将建立链表的方法改为头插入法。
五、实验报告要求
1、基本要求见第一页内容。
2、写出实验结果,并画出所建链表的示意图。
实验二、二叉树操作
一、 目的
掌握二叉树的定义、性质及存储方式,各种遍历算法。
二、 要求
采用二叉树链表作为存储结构,完成二叉树的建立,先序、中序和后序以及按层次遍历的操作,求所有叶子及结点总数的操作。
三、 示例程序
#include"stdio.h"
#include"string.h"
#defineMax20//结点的最大个数
typedefstructnode{
chardata;
structnode*lchild,*rchild;
}BinTNode;//自定义二叉树的结点类型
typedefBinTNode*BinTree;//定义二叉树的指针
intNodeNum,leaf;//NodeNum为结点数,leaf为叶子数
//==========基于先序遍历算法创建二叉树==============
//=====要求输入先序序列,其中加入虚结点“#”以示空指针的位置==========
BinTreeCreatBinTree(void)
{
BinTreeT;
charch;
if((ch=getchar())=='#')
return(NULL);//读入#,返回空指针
else{
T=(BinTNode*)malloc(sizeof(BinTNode));生成结点
T->data=ch;
T->lchild=CreatBinTree();//构造左子树
T->rchild=CreatBinTree();//构造右子树
return(T);
}
}
//========NLR先序遍历=============
voidPreorder(BinTreeT)
{
if(T){
printf("%c",T->data);//访问结点
Preorder(T->lchild);//先序遍历左子树
Preorder(T->rchild);//先序遍历右子树
}
}
//========LNR中序遍历===============
voidInorder(BinTreeT)
{
if(T){
Inorder(T->lchild);//中序遍历左子树
printf("%c",T->data);//访问结点
Inorder(T->rchild);//中序遍历右子树
}
}
//==========LRN后序遍历============
voidPostorder(BinTreeT)
{
if(T){
Postorder(T->lchild);//后序遍历左子树
Postorder(T->rchild);//后序遍历右子树
printf("%c",T->data);//访问结点
}
}
//=====采用后序遍历求二叉树的深度、结点数及叶子数的递归算法========
intTreeDepth(BinTreeT)
{
inthl,hr,max;
if(T){
hl=TreeDepth(T->lchild);//求左深度
hr=TreeDepth(T->rchild);//求右深度
max=hl>hr?
hl:
hr;//取左右深度的最大值
NodeNum=NodeNum+1;//求结点数
if(hl==0&&hr==0)leaf=leaf+1;//若左右深度为0,即为叶子。
return(max+1);
}
elsereturn(0);
}
//====利用“先进先出”(FIFO)队列,按层次遍历二叉树==========
voidLevelorder(BinTreeT)
{
intfront=0,rear=1;
BinTNode*cq[Max],*p;//定义结点的指针数组cq
cq[1]=T;//根入队
while(front!
=rear)
{
front=(front+1)%NodeNum;
p=cq[front];//出队
printf("%c",p->data);//出队,输出结点的值
if(p->lchild!
=NULL){
rear=(rear+1)%NodeNum;
cq[rear]=p->lchild;//左子树入队
}
if(p->rchild!
=NULL){
rear=(rear+1)%NodeNum;
cq[rear]=p->rchild;//右子树入队
}
}
}
//==========主函数=================
voidmain()
{
BinTreeroot;
inti,depth;
printf("\n");
printf("CreatBin_Tree;Inputpreorder:
");//输入完全二叉树的先序序列,
//用#代表虚结点,如ABD###CE##F##
root=CreatBinTree();//创建二叉树,返回根结点
do{//从菜单中选择遍历方式,输入序号。
printf("\t**********select************\n");
printf("\t1:
PreorderTraversal\n");
printf("\t2:
IorderTraversal\n");
printf("\t3:
Postordertraversal\n");
printf("\t4:
PostTreeDepth,Nodenumber,Leafnumber\n");
printf("\t5:
LevelDepth\n");//按层次遍历之前,先选择4,求出该树的结点数。
printf("\t0:
Exit\n");
printf("\t*******************************\n");
scanf("%d",&i);//输入菜单序号(0-5)
switch(i){
case1:
printf("PrintBin_treePreorder:
");
Preorder(root);//先序遍历
break;
case2:
printf("PrintBin_TreeInorder:
");
Inorder(root);//中序遍历
break;
case3:
printf("PrintBin_TreePostorder:
");
Postorder(root);//后序遍历
break;
case4:
depth=TreeDepth(root);//求树的深度及叶子数
printf("BinTreeDepth=%dBinTreeNodenumber=%d",depth,NodeNum);
printf("BinTreeLeafnumber=%d",leaf);
break;
case5:
printf("LevePrintBin_Tree:
");
Levelorder(root);//按层次遍历
break;
default:
exit
(1);
}
printf("\n");
}while(i!
=0);
}
四、 实验内容
1、分析、理解程序。
2、调试程序,设计一棵二叉树,输入完全二叉树的先序序列,用#代表虚结点(空指针),如ABD###CE##F##,建立二叉树,求出先序、中序和后序以及按层次遍历序列,求所有叶子及结点总数。
五、 实验报告要求
1、基本要求见第一页。
2、画出所设计的二叉树,以后序遍历算法为例,画出执行踪迹示意图。
3、给出实验结果。
实验三、图的遍历操作
一、 目的
掌握有向图和无向图的概念;掌握邻接矩阵和邻接链表建立图的存储结构;掌握DFS及BFS对图的遍历操作;了解图结构在人工智能、工程等领域的广泛应用。
二、 要求
采用邻接矩阵和邻接链表作为图的存储结构,完成有向图和无向图的DFS和BFS操作。
三、 DFS和BFS的基本思想
深度优先搜索法DFS的基本思想:
从图G中某个顶点Vo出发,首先访问Vo,然后选择一个与Vo相邻且没被访问过的顶点Vi访问,再从Vi出发选择一个与Vi相邻且没被访问过的顶点Vj访问,……依次继续。
如果当前被访问过的顶点的所有邻接顶点都已被访问,则回退到已被访问的顶点序列中最后一个拥有未被访问的相邻顶点的顶点W,从W出发按同样方法向前遍历。
直到图中所有的顶点都被访问。
广度优先算法BFS的基本思想:
从图G中某个顶点Vo出发,首先访问Vo,然后访问与Vo相邻的所有未被访问过的顶点V1,V2,……,Vt;再依次访问与V1,V2,……,Vt相邻的起且未被访问过的的所有顶点。
如此继续,直到访问完图中的所有顶点。
四、 示例程序
1. 邻接矩阵作为存储结构的程序示例
#include"stdio.h"
#include"stdlib.h"
#defineMaxVertexNum100//定义最大顶点数
typedefstruct{
charvexs[MaxVertexNum];//顶点表
intedges[MaxVertexNum][MaxVertexNum];//邻接矩阵,可看作边表
intn,e;//图中的顶点数n和边数e
}MGraph;//用邻接矩阵表示的图的类型
//=========建立邻接矩阵=======
voidCreatMGraph(MGraph*G)
{
inti,j,k;
chara;
printf("InputVertexNum(n)andEdgesNum(e):
");
scanf("%d,%d",&G->n,&G->e);//输入顶点数和边数
scanf("%c",&a);
printf("InputVertexstring:
");
for(i=0;in;i++)
{
scanf("%c",&a);
G->vexs[i]=a;//读入顶点信息,建立顶点表
}
for(i=0;in;i++)
for(j=0;jn;j++)
G->edges[i][j]=0;//初始化邻接矩阵
printf("Inputedges,CreatAdjacencyMatrix\n");
for(k=0;ke;k++){//读入e条边,建立邻接矩阵
scanf("%d%d",&i,&j);//输入边(Vi,Vj)的顶点序号
G->edges[i][j]=1;
G->edges[j][i]=1;//若为无向图,矩阵为对称矩阵;若建立有向图,去掉该条语句
}
}
//=========定义标志向量,为全局变量=======
typedefenum{FALSE,TRUE}Boolean;
Booleanvisited[MaxVertexNum];
//========DFS:
深度优先遍历的递归算法======
voidDFSM(MGraph*G,inti)
{//以Vi为出发点对邻接矩阵表示的图G进行DFS搜索,邻接矩阵是0,1矩阵
intj;
printf("%c",G->vexs[i]);//访问顶点Vi
visited[i]=TRUE;//置已访问标志
for(j=0;jn;j++)//依次搜索Vi的邻接点
if(G->edges[i][j]==1&&!
visited[j])
DFSM(G,j);//(Vi,Vj)∈E,且Vj未访问过,故Vj为新出发点
}
voidDFS(MGraph*G)
{
inti;
for(i=0;in;i++)
visited[i]=FALSE;//标志向量初始化
for(i=0;in;i++)
if(!
visited[i])//Vi未访问过
DFSM(G,i);//以Vi为源点开始DFS搜索
}
//===========BFS:
广度优先遍历=======
voidBFS(MGraph*G,intk)
{//以Vk为源点对用邻接矩阵表示的图G进行广度优先搜索
inti,j,f=0,r=0;
intcq[MaxVertexNum];//定义队列
for(i=0;in;i++)
visited[i]=FALSE;//标志向量初始化
for(i=0;in;i++)
cq[i]=-1;//队列初始化
printf("%c",G->vexs[k]);//访问源点Vk
visited[k]=TRUE;
cq[r]=k;//Vk已访问,将其入队。
注意,实际上是将其序号入队
while(cq[f]!
=-1){//队非空则执行
i=cq[f];f=f+1;//Vf出队
for(j=0;jn;j++)//依次Vi的邻接点Vj
if(G->edges[i][j]==1&&!
visited[j]){//Vj未访问
printf("%c",G->vexs[j]);//访问Vj
visited[j]=TRUE;
r=r+1;cq[r]=j;//访问过Vj入队
}
}
}
//==========main=====
voidmain()
{
inti;
MGraph*G;
G=(MGraph*)malloc(sizeof(MGraph));//为图G申请内存空间
CreatMGraph(G);//建立邻接矩阵
printf("PrintGraphDFS:
");
DFS(G);//深度优先遍历
printf("\n");
printf("PrintGraphBFS:
");
BFS(G,3);//以序号为3的顶点开始广度优先遍历
printf("\n");
}
执行顺序:
V6
V4
V5
V7
V2
V3
V1
V0
Vo
图G的示例
InputVertexNum(n)andEdgesNum(e):
8,9
InputVertexstring:
01234567
Inputedges,CreatAdjacencyMatrix
01
02
13
14
25
26
37
47
56
PrintGraphDFS:
01374256
PrintGraphBFS:
31704256
2. 邻接链表作为存储结构程序示例
#include"stdio.h"
#include"stdlib.h"
#defineMaxVertexNum50//定义最大顶点数
typedefstructnode{//边表结点
intadjve