数据结构课程设计论文.docx
- 文档编号:9218805
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:29
- 大小:181.45KB
数据结构课程设计论文.docx
《数据结构课程设计论文.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计论文.docx(29页珍藏版)》请在冰豆网上搜索。
数据结构课程设计论文
《数据结构(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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程设计 论文