单链表的插入和删除实验报告.docx
《单链表的插入和删除实验报告.docx》由会员分享,可在线阅读,更多相关《单链表的插入和删除实验报告.docx(23页珍藏版)》请在冰豆网上搜索。
单链表的插入和删除实验报告
实验一、单链表的插入和删除
一、目的
了解和掌握线性表的逻辑结构和链式存储结构,掌握单链表的基本算法及相关的时间性能分析。
二、要求:
建立一个数据域定义为字符串的单链表,在链表中不允许有重复的字符串;根据输入的字符串,先找到相应的结点,后删除之。
三、程序源代码
#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()
{
charch[10],num[10];
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)
{
charch[10];
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(p&&strcmp(p-〉data,key)!
=0)//直到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);
}
运行结果:
加的添加结点的代码:
intInsert(ListNode*head)//theinsertfunction
{
ListNode*in,*p,*q;
intwh;
printf("inputtheinsertnode:
");
in=(ListNode*)malloc(sizeof(ListNode));in-〉next=NULL;
p=(ListNode*)malloc(sizeof(ListNode));p—〉next=NULL;
q=(ListNode*)malloc(sizeof(ListNode));q—〉next=NULL;
if(!
in)
return0;
scanf(”%s”,in—〉data);
printf("inputtheplacewhereyouwanttoinsertyoudata:
”);
scanf(”%d",&wh);
for(p=head;wh〉0;p=p—〉next,wh--);
q=p—>next;
p—〉next=in;
in->next=q;
return1;
}
运行结果:
最后提示为OK添加成功。
实验心得:
这个实验中主要修改的是ch和num把它们由指针改成数组因为不改的话在后面delect函数中会出现没有地址的情况找不到地址就不能执行功能然后把locate函数的判断语句改一下避免矛盾的出现。
实验二、二叉树操作
一、目的
掌握二叉树的定义、性质及存储方式,各种遍历算法。
二、要求
采用二叉树链表作为存储结构,完成二叉树的建立,先序、中序和后序以及按层次遍历的操作,求所有叶子及结点总数的操作。
三、程序源代码
#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.中序遍历
3.后序遍历
4.结点数叶子数高度
5..层次遍历
自己设计的:
abdhl##m##i##e#jn###cf#ko###g##
1。
预计先序遍历结果:
abdhlmiejncfkog
2。
预计中序遍历结果:
lhmdibenjafokcg
3.预计后序遍历结果:
lmhidnjebokfgca
4.结点数15高度5叶子数6
实际结果:
实验心得:
这次实验主要是要让我们熟练树及其相关知识熟练掌握先序中序后序遍历,层次遍历然后我们自己画一个图会实现以上功能以及叶子数结点数还有高度的计算程序里面大量运用了递归以及队的应用,
实验三、图的遍历操作
一、目的
掌握有向图和无向图的概念;掌握邻接矩阵和邻接链表建立图的存储结构;掌握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;i〈G-〉n;i++)
for(j=0;jn;j++)
G->edges[i][j]=0;//初始化邻接矩阵
printf("Inputedges,CreatAdjacencyMatrix\n");
for(k=0;kscanf(”%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;j〈G—>n;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;ivisited[i]=FALSE;//标志向量初始化
for(i=0;i〈G-〉n;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;i〈G—>n;i++)
visited[i]=FALSE;//标志向量初始化
for(i=0;i〈G—>n;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");
}
调试结果:
自己画的图:
1对应顶点下标0以此类推9对应下标8
预计运行结果:
DFS:
012345678
BFS:
324105687
对应我这个图:
DFS:
123456789
BFS:
435216798
实验心得:
图在数据结构中是相当重要的一部分联系很多现实问题图的根本就是顶点和边通过顶点和边建立邻接矩阵以及邻接链表广度搜索和深度搜索是此算法着重关注的地方.要学会自己画图然后写出这两种搜索的结果,程序中用了队的算法是亮点通过TRUE和FAUSE来标记顶点是否以及访问避免重复
实验四、排序
一、目的
掌握各种排序方法的基本思想、排序过程、算法实现,能进行时间和空间性能的分析,根据实际问题的特点和要求选择合适的排序方法.
二、要求
实现直接排序、冒泡、直接选择、快速、堆、归并排序算法。
比较各种算法的运行速度。
三、程序示例
#include"stdio.h"
#include”stdlib。
h"
#defineMax100//假设文件长度
typedefstruct{//定义记录类型
intkey;//