数据结构课程设计论文.docx

上传人:b****7 文档编号:9218805 上传时间:2023-02-03 格式:DOCX 页数:29 大小:181.45KB
下载 相关 举报
数据结构课程设计论文.docx_第1页
第1页 / 共29页
数据结构课程设计论文.docx_第2页
第2页 / 共29页
数据结构课程设计论文.docx_第3页
第3页 / 共29页
数据结构课程设计论文.docx_第4页
第4页 / 共29页
数据结构课程设计论文.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

数据结构课程设计论文.docx

《数据结构课程设计论文.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计论文.docx(29页珍藏版)》请在冰豆网上搜索。

数据结构课程设计论文.docx

数据结构课程设计论文

《数据结构(C语言版)》

——课程设计报告——

院系:

信息科学与技术学院

设计题目:

无向网邻接矩阵的建立、

无向网的遍历与普里姆算法的实现,

有向图邻接表的建立

专业班级:

学号:

姓名:

指导教师:

设计日期:

2011年12月21日

 

摘要:

仅仅学习理论而脱离实践,往往会变成“纸上谈兵”。

本课程设计用C语言作基础,以源程序的形式具体实现了数据结构中,无向网邻接矩阵的建立、无向网邻接矩阵的遍历、普里姆算法求最优树以及有向图邻接表的建立。

关键词:

数据结构邻接矩阵遍历普里姆算法邻接表

目录

1.课程设计的内容----------------------------------------------------------------------3

1.1无向网部分---------------------------------------------------------------------3

1.2有向图部分---------------------------------------------------------------------3

2.课程设计中所用的函数说明-------------------------------------------------------3

2.1无向网部分---------------------------------------------------------------------3

2.2有向图部分---------------------------------------------------------------------3

3.算法的设计思想----------------------------------------------------------------------3

3.1邻接矩阵的建立---------------------------------------------------------------3

3.2邻接矩阵的初始化------------------------------------------------------------4

3.3邻接矩阵的输出---------------------------------------------------------------5

3.4邻接矩阵的遍历---------------------------------------------------------------5

3.5普里姆最小生成树------------------------------------------------------------6

3.6邻接表的建立-----------------------------------------------------------------9

4.运行结果-------------------------------------------------------------------------------12

4.1无向网部分---------------------------------------------------------------------12

4.2有向图部分---------------------------------------------------------------------14

5.时间复杂度说明----------------------------------------------------------------------16

6.心得体会-------------------------------------------------------------------------------17

参考文献---------------------------------------------------------------------------------18

附录:

C语言代码清单----------------------------------------------------------------19

1.课程设计的内容

1.1无向网部分:

无向网邻接矩阵的建立,无向网邻接矩阵的遍历,普里姆算法(最优生成树)的实现。

1.2有向图部分:

有向图邻接表的建立。

2.课程设计中所用的函数说明

2.1无向网部分:

函数名称

函数功能

creatMGraph

创建一张无向网的邻接矩阵

printMGraph

输出一张无向网的邻接矩阵

DFS

遍历一张无向网

MiniSpanTree_PRIM

实现基于无向网的普里姆算法,即生成最优树

2.2有向图部分:

函数名称

函数功能

creatALGraph

创建一张有向图的邻接表

printfALGraph

输出一张有向图的邻接表

3.算法的设计思想

3.1邻接矩阵的建立

邻接矩阵表示顶点之间的相邻关系,设

,是具有n个顶点的网,则G的邻接矩阵是具有如下性质的n阶方阵:

(1)如果顶点

相连,则

赋值为权值,否则为无穷大(本课设中采用最大数代替无穷大)。

(2)对于无向网,

用邻接矩阵表示法表示网,除了存储邻接矩阵外,通常还需要用一个顺序表来存储顶点信息。

其具体C语言代码如下:

#definevexnum6/*图的顶点数目*/

#definearcnum10/*图的边(弧)数目*/

intvisited[vexnum]={0};/*顶点是否被遍历的标志数组*/

typedefstruct{/*创建一个用邻接矩阵表示的图*/

intvexs[vexnum];/*顶点信息*/

floatarcs[vexnum][vexnum];/*邻接矩阵*/

}MGraph;

3.2邻接矩阵的初始化

由于无向网的邻接矩阵是对称的,故可采用压缩存储的方法,仅存储下三角阵(不包括对角线上的元素)中的元素。

显然,邻接矩阵表示法的空间复杂度

邻接矩阵的建立过程如下代码所示:

voidcreatMGraph(MGraph*m)/*向一个用邻接矩阵表示的图中输入数值*/

{

inti,j,k;

floatwqd;/*因为后面要应用普里姆算法,故设置“无穷大”为wqd*/

floatw;

for(i=0;i

{

printf("请输入顶点(%d):

",i);/*输入第i号顶点的数据*/

scanf("%d",&m->vexs[i]);

}

printf("请输入权值最大范围0--:

");/*确定最大值,即“无穷大”,一般输入一个比最大值再大一些的数字作为“无穷大”*/

scanf("%f",&wqd);

for(i=0;i

for(j=0;j

m->arcs[i][j]=wqd;/*邻接矩阵初始化,全部赋值无穷大*/

for(k=0;k

{

inta=arcnum;

intb=(vexnum-1);

printf("请输入边(1-%d)与权值(顶点0--%d):

",a,b);/*提示信息*/

scanf("%d%d%f",&i,&j,&w);/*读入边

上的权w*/

m->arcs[i][j]=w;

m->arcs[j][i]=w;

}

}

3.3邻接矩阵的输出

本课设采用行列式的形式输出邻接矩阵,具体C语言代码如下:

voidprintMGraph(MGraph*m)

{

inti,j;

printf("");/*格式*/

for(i=0;i

printf("%d(%d)",m->vexs[i],i);/*输出格式为“顶点信息(顶点编号)”*/

printf("\n");

printf("---");

for(i=0;i

printf("------------");/*下横线*/

printf("\n");

for(i=0;i

{

printf("%d(%d)|",m->vexs[i],i);

for(j=0;j

printf("%f",m->arcs[i][j]);/*依次输出每一个顶点与其他顶点的关系*/

printf("\n");

}

}

3.4邻接矩阵的遍历

对于图的遍历,和树的遍历类似,也是从某个顶点出发,沿着某条搜索路径对图中所有顶点做一次访问。

若给定的图是连通图,则从图中任一顶点出发顺着边可以访问到该图的所有顶点。

又因为图中任一顶点都可能和其余顶点相邻接,故在访问了某个顶点之后,可能顺着某条回路又回到了该顶点。

为了避免重复访问同顶点,必须记住每个顶点是否被访问过。

为此,我们已经在前面设置了向量intvisited[vexnum]={0}来标识。

它的初值为0,一旦访问了顶点

,便将顶点

置为1。

邻接矩阵遍历的具体C语言代码如下:

voidDFS(MGraph*m,inti)/*从邻接矩阵的第i个顶点开始遍历*/

{

intj;

visited[i]=1;/*i号顶点标识为1,代表已经遍历过了*/

printf("%d-",i);/*输出已经遍历的顶点序号*/

for(j=0;j

if((m->arcs[i][j]!

=0)&&(visited[j]==0))/*只有当顶点i与另外一个顶点j相邻且j顶点没有被遍历过的时候,才采用递归遍历*/

DFS(m,j);/*递归遍历j顶点*/

printf("\b");/*退格键,去掉最后一个“-”*/

printf("\n");

}

3.5普里姆最小生成树

不少图论问题在计算时,往往首先必须求出一棵最小生成树。

是一个无向图,如果

是由G的全部顶点及一部分边组成的子图,并且T是树(连通,没有环的图),则称T是G的一棵生成树。

一个连通图G的生成树不是唯一的,从不同的顶点出发进行遍历,得到不同的生成树。

对于连通网络

,边是带权的,因而G的生成树的各边也是带权的。

我们把生成树各边的权值总和称为生成树的权,并把权最小的生成树称为G的最小生成树。

最小生成树有许多重要的应用。

令图G的顶点表示城市,边表示连接两个城市之间的通信线路。

n个城市之间最多可设立的线路有

条,把n个城市连接起来至少要有n-1条线路,则图G的生成树表示了建立通信网络的可行方案。

如果给图中的边都赋予权,则这些权可表示两个城市之间通信线路的长度或建造代价,那么,如何选择一条线路,使得建立的n-1条通信网络其线路的总长度最短或总代价最小呢?

这就需要构造该图的一棵最小生成树。

本课设采用普里姆算法生成一个无向网的最优生成树。

基本思想为:

在所有

的边

中找到一条代价最小的边

并入最小生成树边的集合

中,同时

并入

,直至

为止。

为此,需要特别说明一个辅助矩阵——closedge,本课设中closedge的定义是这样的:

closedge为一个结构体数组,每一个结构体由两部分组成,一个是U集合中对应于第i号元素的边的集合中,最小权值的顶点序号,实际上就是两个顶点(i和closedge.adjvex)所确定的边;另一个是该边上的权值。

数组closedge代码如下:

typedefstruct{/*辅助功能,用来选择最小生成树的边*/

intadjvex;/*顶点序号*/

floatlowcost;/*最小权值*/

}closedge;

首先,我们从邻接矩阵中选一个顶点开始查找,设该顶点序号为u,将辅助数组closedge中的所有元素依次赋值为与顶点u对应的边的信息,而顶点u的lowcost的值为0,表明此顶点已经并入集合U之中了。

然后,我们搜索数组closedge,从中找到权值最小的边所对应的序号,此序号所表示的顶点即为下一个进入集合U的顶点。

接下来,我们对剩下的vexnum-1个顶点进行同样的逐个查找,依次找出每个顶点所对应的,当前集合U中的(集合U是不断变化的),与之所形成的边的最小值,将最小值赋给lowcost,对应集合U中的顶点序号赋给adjvex。

依次往复,即可找出所有最有树的边。

但是,我发现书中的算法出现了一个小小的错误,即175页中算法7.9正数第二个for循环中,i

中仅剩下一个顶点元素,所以无需再进行比较,直接插入最优树即可,也就是说,最后一次循环中,数组closedge仅剩下一个顶点的lowcost不等于0,其所对应的adjvex即为需要连接进入集合U的顶点。

相应的,在书中算法7.9的结尾,也应当编写一段类C语言说明最后一次循环的情况。

具体普里姆算法C语言代码如下:

voidMiniSpanTree_PRIM(MGraph*m,intu)/*u为开始顶点编号*/

{

intk,i,j;

closedgecs[vexnum];

for(j=0;j

if(j!

=u)

{

cs[j].lowcost=m->arcs[u][j];

cs[j].adjvex=u;

}

cs[u].lowcost=0;/*表明已进入顶点集U*/

floatsum=0.0;/*用于计算最小权值总和*/

for(i=1;i<(vexnum-1);i++)/*对剩余的vexnum-2个顶点(循环次数)*/

{

intp;/*找出数组cs中的最小权值所对的序号(lowcost为MAX的除外)*/

floatmax=0.0;

for(p=0;p

if(max

max=cs[p].lowcost;

floatmin=max;

for(p=0;p

if((cs[p].lowcost!

=0)&&(min>cs[p].lowcost))

{min=cs[p].lowcost;

k=p;/*下一个进入集合U的顶点编号,即V-U中的最小权值顶点*/

}

printf("%d---%d最小权值为%f",cs[k].adjvex,k,cs[k].lowcost);

sum=sum+cs[k].lowcost;/*求权值*/

printf("\n");

cs[k].lowcost=0;/*表明已进入顶点集U*/

for(j=0;j

if(m->arcs[k][j]

{

cs[j].adjvex=k;/*相对于上一个u而言,k所对应的权值更小*/

cs[j].lowcost=m->arcs[k][j];

}

}

for(i=0;i

if(cs[i].lowcost!

=0)k=i;/*最后一个进入集合U的顶点序号*/

printf("%d---%d最小权值为%f",cs[k].adjvex,k,cs[k].lowcost);

printf("\n");

printf("该最小生成树权值总和为:

%f",sum);

printf("\n");

}

3.6邻接表的建立

邻接表是把图的每个顶点的邻接顶点用链接表表示,这种表示方法类似于树的孩子链表表示法。

为此,需要建立一个顺序存储n个顶点的表,针对图G中的每个顶点

,该方法把所有邻接于

的顶点

链成一个单链表,这个单链表就称为顶点

的邻接表。

邻接表中每个表结点均有两个域,其一是邻接域,用以存放与

相邻接的顶点

的序号;其二是链接域,用来指向与顶点

相邻的下一个顶点,这样,就可以将邻接表的所有表结点链接在一起。

同时,为每个顶点

的邻接表设置一个具有两个域的表头结点,一个是顶点域,用来存放顶点

的信息。

另一个是指针域,用于存入指向

的邻接表中第一个表结点的头指针。

其具体C语言代码如下:

#definevexnum6

#definearcnum5

typedefstruct{/*表头结点*/

intadjvex;

structArcnode*next;

}Arcnode;

typedefstructVnode{/*表结点*/

intdata;

structArcnode*next;

}Vnode;

typedefstruct{/*用邻接表表示的有向图*/

VnodeGmap[vexnum];

}ALGraph;

/*————————————邻接表的建立————————————*/

voidcreatALGraph(ALGraph*m)

{

inti,j,k;

for(i=0;i

{

m->Gmap[i].data=0;

m->Gmap[i].next=NULL;

}

for(i=0;i

{

printf("请输入顶点(%d)数值:

",i);

scanf("%d",&m->Gmap[i].data);

}

for(k=0;k

{

inta=(vexnum-1);

printf("请输入有向边“弧头弧尾”(以0为起点,0-%d):

",a);

scanf("%d%d",&i,&j);

Arcnode*q=(Arcnode*)malloc(sizeof(Arcnode));/*开辟一个新的结点空间,并且从表头插入*/

q->adjvex=i;

q->next=m->Gmap[j].next;

m->Gmap[j].next=q;

}

}

/*——————————邻接表的输出————————————*/

voidprintfALGraph(ALGraph*m)

{

inti;

for(i=0;i

{

printf("%d(%d)|",m->Gmap[i].data,i);/*输出顶点信息,顶点序号*/

Arcnode*p=m->Gmap[i].next;

while(p!

=NULL)/*从表头输出至表尾*/

{

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

p=p->next;

}

printf("\b");/*退格键,去掉最后一个“-”*/

printf(“\n”);

}

}

4.运行结果

运行环境:

MicrosoftVisualC++

程序语言:

C语言

下面,我们来检验一下程序能否正确运行。

4.1无向网部分

如图所示,为一张无向网。

主程序main()编写如下:

voidmain()

{

intv;

MGraphg={{0},{0}};/*无向网的初始化*/

MGraph*y=&g;

creatMGraph(y);/*输入无向网的信息*/

printf("\n");

printf("无向网的邻接矩阵如下:

");

printf("\n");

printMGraph(y);/*输出无向网的邻接矩阵*/

printf("无向网的遍历如下:

");

printf("\n");

for(v=0;v

if(!

visited[v])DFS(y,v);

printf("\n");

printf("依据普里姆算法,得该图的最小生成树为:

");

printf("\n");

intu=0;/*从序号为0的顶点开始普里姆算法*/

MiniSpanTree_PRIM(y,u);/*无向网的最小生成树*/

}

运行步骤:

1.编译无误,运行,界面如下所示

2.输入顶点

3.输入“无穷大”值,譬如90

4.输入各条边的信息

5.运行结果为

因为程序设置的是浮点型数据(float),故输出结果中会有一些误差。

其余的结果皆正确。

4.2有向图部分

如图所示,为一张有向图

主程序main()编写如下:

voidmain()

{

ALGraphm={{0,NULL}};/*有向图的初始化*/

ALGraph*g=&m;

creatALGraph(g);/*输入有向图的信息*/

printf("该有向图的邻接表如下所示:

");

printf("\n");

printfALGraph(g);/*输出邻接表*/

}

运行步骤:

1.编译无误,运行,界面如下所示

2.输入顶点信息

3.输入各条边的信息

4.运行结果

与原图对照,可知结果正确。

5.时间复杂度说明

构造一个具有n个顶点和e条边的无向网MGraph的时间复杂度是

,其中对邻接矩阵MGraph.arcs的初始化耗费了

的时间。

假设网中有n个顶点,对用邻接矩阵表示的无向网进行遍历所需的时间复杂度为

对普里姆算法而言,第一个进行初始化的循环语句的频度为n,第二个循环语句的频度为n-1。

其中有2个内循环:

其一是在cs[v].lowcost中求最小值,其频度为n-1;其二是重新选择具有最小代价的边,其频度为n。

由此,普里姆算法的时间复杂度为

,与网中的边数无关,因此适用于求边稠密的网的最小生成树。

建立有向图的邻接表的时间复杂度为

6.心得体会

数据结构这门课的思想性很强,它包纳了线性表、树、图等等逻辑结构。

但学习这门课,光靠上课听讲还远远不能满足学习的需要,必须亲自编写源程序,不断地调试、运行、反复地思考,才能加深对本学科的认识,强化对所学知识的应用。

我认为,数据结构的相关知识和C语言的学习完全可以融为一体,一方面学习算法思想,另一方面用语言去实践。

相得益彰,趣味盎然。

 

参考文献

严蔚敏吴伟民.数据结构(C语言版).北京:

清华大学出版社.1992年4月

徐孝凯贺桂英.数据结构(C语言描述).北京:

清华大学出版社.2004年2月

李克清夏祥胜崔洪芳.数据结构——C语言描述.武汉:

华中科技大学出版社.2004年12月

附录:

C语言代码清单

1.无向网部分

#include

#include

#definevexnum6

#definearcn

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

当前位置:首页 > 总结汇报 > 其它

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

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