当前位置:文档之家› 最小生成树数据结构课程设计报告

最小生成树数据结构课程设计报告

河北科技大学课程设计报告学生姓名:白云学号:Z********* 专业班级:计算机113班课程名称:数据结构课程设计学年学期: 2 01 3—2 014学年第2学期指导教师:**2014年6月课程设计成绩评定表目录一、需求分析说明 (1)1.1最小生成树总体功能要求 (1)1.2基本功能 (1)1.3 模块分析 (1)二、概要设计说明 (1)2.1设计思路 (1)2.2模块调用图 (2)2.3数据结构设计 (2)2.3.1.抽象数据类型 (2)2.3.2方法描述 (2)三、详细设计说明 (3)3.1主函数模块 (3)3.2邻接表输出子模块 (3)3.3邻接矩阵输出子模块 (3)3.4创建邻接矩阵子模块 (3)3.5创建邻接表子模块 (3)3.6 Prim子模块 (3)3.7 Kruscal子模块 (4)四、调试分析 (4)4.1实际完成情况说明 (4)4.2 出现的问题及解决方案 (4)4.3程序中可以改进的地方 (4)六、课程设计总结 (7)七、测试数据 (7)八、参考书目 (7)一、需求分析说明1.1最小生成树总体功能要求在n个城市之间建设网络,只需保证连通即可,求最经济的架设方法。

存储结构采用多种。

求解算法多种。

1.2基本功能在n个城市之间建设网络,只需要架设n-1条线路,建立最小生成树即可实现最经济的架设方法。

程序可利用克鲁斯卡尔算法或prim算法生成最小生成树。

1.3 模块分析主模块:用于生成界面和调用各个子模块。

Kruscal模块:以kruscal算法实现最小生成树。

Prim模块:以prim算法实现最小生成树。

邻接表模块:用邻接表方式存储图。

邻接表输出模块:输出邻接表。

邻接矩阵模块:用邻接矩阵方式存储图。

邻接矩阵模块:输出邻接矩阵。

二、概要设计说明2.1设计思路问题的解决分别采用普利姆算法以及克鲁斯卡尔算法。

1) 普利姆算法就是先选择根,把它放入一个集合U中,剩余的顶点放在集合V中。

然后选择该顶点与V中顶点之间权值最小的一条边,以此类推,如果达到最后一个则返回上一个顶点。

2) 克鲁斯卡尔算法就是写出所有的顶点,选择权最小的边,然后写出第二小的,以此类推,最终要有一个判断是否生成环,不生成则得到克鲁斯卡尔的最小生成树。

2.2模块调用图2.3数据结构设计2.3.1.抽象数据类型ADT Graph{数据对象 V:v是具有相同特征的数据元素的集合,成为顶点集。

数据关系 R:R={VR}VR={<v,w>|v,w属于v且p(v,w)表示从v到w的弧,谓词p(v,w)定义了弧<v,w>的意义或信息}基本操作:1)GreatGraph(&G,V,VR)初始条件:V是图的顶点集,VR是图中弧的集合。

操作条件:按V和VR的定义构造图G。

2)LocateVex(G,u)初始条件:图G存在,u和G中顶点有相同的特征。

操作条件:若G中存在顶点u,则返回该顶点在图中的位置,否则返回其他信息。

2.3.2方法描述#define int_max 10000 /*节点不可达的距离*/#define max 20 /*数组最大长度*/int creatMGraph_L(MGraph_L &G) //用邻接矩阵存储void ljjzprint(MGraph_L G) //输出邻接矩阵int creatadj(algraph &gra,MGraph_L G) //用邻接表存储图void adjprint(algraph gra) //输出邻接表int prim(int g[][max],int n) //prim算法void kruscal_arc(MGraph_L G ,algraph gra) //最小生成树kruscal算法三、详细设计说明3.1主函数模块首先调用creatMGraph_L()函数进行邻接矩阵的初始化,然后调用creatadj()函数进行邻接表的初始化,然后根据用户输入判断switch()调用哪个模块。

3.2邻接表输出子模块首先判断是否超出了数据的个数,如果没有则输出邻接表的头节点,如果头节点的指针域不为空则输出下一个表结点,以此类推。

3.3邻接矩阵输出子模块判断是否超出了数据的个数,如果没有则输出G.arcs[i][j].adj中的值。

3.4创建邻接矩阵子模块输入顶点和弧的个数,再输入顶点与顶点之间的权值,生成邻接矩阵3.5创建邻接表子模块根据表结构定义一个表,设置表头结点为空,再循环生成其它结点并连接到上一个结点的后面。

3.6 Prim子模块标志顶点1加入U集合,形成n-1条边的生成树,寻找满足边的一个顶点在U,另一个顶点在V中的最小边,顶点K加入U,修改由顶点K到其他顶点边的权值,最后得到最小生成树。

3.7 Kruscal子模块确定弧的结点,以及弧的权,比较弧的权的大小并对权小的赋值,确定结点的位置,确保不能生成换,最后的到最小生成树。

四、调试分析4.1实际完成情况说明程序完成了prim和kruscal求一个图的最小生成树,并对图以邻接表和邻接矩阵的形式进行存储。

4.2 出现的问题及解决方案1)数据之间类型不同,引发数据间交换紊乱。

指针空间未分配导致系统随机给出一个错误的数据2)在寻找下一个结点时,寻找到最小权值边,将其两端的顶点信息及变的权值存储道辅助数组中。

在设计解决这些问题时用多个for循环嵌套查找,判断。

3)一些小细节尤其要注意,比如变量的定义,定义的位置。

4.3程序中可以改进的地方程序中对于一些没有最小生成树的图,没有判断功能。

还有就是进行完一个图的运算要关闭程序再重新输入新的图。

五、用户使用说明输入正确的数据程序执行菜单邻接矩阵存储邻接表存储Prim算法Kruscal算法六、课程设计总结通过这次课程设计,我收获了不少的东西。

我选择的题目是最小生成树,这个问题看这简单,但是做起来有非常大的困难。

平时我们很注重理论学习,但现在看来,实践也是非常重要的,两者缺一不可。

在这期间我遇到了不少的问题,问同学,查资料,虽然过程是辛苦琐碎的,但最后成果出来还是很鼓舞人心的。

七、测试数据1:城市的个数和线路个数:5,62:各个城市的名称:a,b,c,d,e3:每条路径的权值:a d 1 , a b 1 , b c 1 , b d 1 , d e 1 , c e 2八、参考书目[1]汤文兵.数据结构.北京:清华大学出版社,2011[2]李春葆.数据结构——习题与解析.北京:清华大学出版社,2010[3]Mark Allen Weiss. Data Structures and Algorithm Analysis in C: Second Edition. New York:MITPress, 2007[4]郭翠英.C语言课程设计案例精编.北京:中国水利出版社,2011源代码#include <iostream.h>#include <malloc.h>#include <stdio.h>//using namespace std;#define int_max 10000#define inf 9999#define max 20typedef struct ArcCell{int adj;char *info;}ArcCell,AdjMatrix[20][20];typedef struct {char vexs[20];//定义一个顶点数组AdjMatrix arcs;//定义一个邻接矩阵int vexnum;int arcnum;}MGraph_L;int localvex(MGraph_L G,char v){int i=0;while(G.vexs[i]!=v){++i;}return i;}int creatMGraph_L(MGraph_L &G){char v1,v2;int i,j,w;cout<<"请输入城市个数和总道路的个数:"<<endl;cin>>G.vexnum>>G.arcnum;for(i=0;i!=G.vexnum;++i){cout<<"输入城市名"<<i+1<<endl;cin>>G.vexs[i];}for(i=0;i!=G.vexnum;i++)for(j=0;j!=G.vexnum;++j){G.arcs[i][j].adj=int_max;G.arcs[i][j].info=NULL;}for(int k=0;k!=G.arcnum;++k){cout<<"请输入两城市之间的距离:"<<endl;cin>>v1>>v2>>w;//输入一条边依附的两点及权值i=localvex(G,v1);j=localvex(G,v2);G.arcs[i][j].adj=w;// G.arcs[j][i].adj=w;}cout<<"***********************************************"<<endl;cout<<"图创建成功"<<endl;cout<<"请根据如下进行操作"<<endl;return G.vexnum;}void ljjzprint(MGraph_L G){//输出邻接矩阵int i,j;for(i=0;i!=G.vexnum;++i){for(j=0;j!=G.vexnum;++j)if(G.arcs[i][j].adj==10000){ cout<<"0"<<" ";}else{cout<<G.arcs[i][j].adj<<" ";}cout<<endl;}}typedef struct arcnode{ //定义表结点int adjvex;//该弧指向的顶点在图中的位置struct arcnode *nextarc;//链域,指向下一条边或弧的结点char *info;//该弧的信息}arcnode;typedef struct vnode{//临街链表顶点头结点char data;//数据arcnode *firstarc;//链域}vnode,adjlist;typedef struct {//表的定义adjlist vertices[max];//定义头结点int vexnum,arcnum;//图的当前顶点数和弧数int kind;//图的种类标志}algraph;typedef struct acr{//弧的定义int pre;//弧的一结点int bak;//弧的另一结点int weight;//弧的权}edg;int creatadj(algraph &gra,MGraph_L G){//用邻接表存储图int i=0,j=0;arcnode *arc,*tem,*p;for( i=0;i!=G.vexnum;++i){//邻接表的初始化gra.vertices[i].data=G.vexs[i];//将abcde放入顶点信息域gra.vertices[i].firstarc=NULL;//指针域为空}for( i=0;i<G.vexnum;i++){for( j=0;j<G.vexnum;j++){if(gra.vertices[i].firstarc==NULL){if(G.arcs[i][j].adj!=int_max&&j<G.vexnum){arc=(arcnode *)malloc(sizeof(arcnode));arc->adjvex=j;gra.vertices[i].firstarc=arc;arc->nextarc=NULL;p=arc;}}else{if(G.arcs[i][j].adj!=int_max&&j!=G.vexnum){tem=(arcnode *)malloc(sizeof(arcnode));tem->adjvex=j;p->nextarc=tem;tem->nextarc=NULL;p=tem;}}}}gra.vexnum=G.vexnum;gra.arcnum=G.arcnum;return 1;}void adjprint(algraph gra){//输出邻接表int i;for(i=0;i!=gra.vexnum;++i){arcnode *p;cout<<gra.vertices[i].data<<i<<"->";p=gra.vertices[i].firstarc;while(p!=NULL){cout<<"->"<<p->adjvex;p=p->nextarc;}cout<<endl;}}typedef struct{int adjvex;int lowcost;}closedge;int prim(int g[][max],int n){//prim算法int lowcost[max],prevex[max];//lowcost[]存储当前集合U分别到剩余结点的最短路径prevex[]存储最短路径在U中的结点int i,j,k,min;for(i=2;i<=n;i++){lowcost[i]=g[1][i];//初始化prevex[i]=1;//顶点未加入到最小生成树中}lowcost[1]=0;//标志顶点1加入U集合for(i=2;i<=n;i++){//形成n-1条边的生成树min=inf;k=0;for(j=2;j<=n;j++)if((lowcost[j]<min)&&(lowcost[j]!=0)){min=lowcost[j];k=j;}printf("(%d,%d) %d\t",prevex[k]-1,k-1,min);lowcost[k]=0;//顶点K加入Ufor(j=2;j<=n;j++)if(g[k][j]<lowcost[j]){lowcost[j]=g[k][j];prevex[j]=k;}printf("\n");}return 0;}int arcvisited[100];//kruscal弧标记数组int find(int arcvisited[] ,int f){while(arcvisited[f]>0)f=arcvisited[f];return f;}void kruscal_arc(MGraph_L G ,algraph gra) {//最小生成树kruscal算法edg edgs[20];int i,j,k=0;for(i=0;i!=G.vexnum;++i)for(j=i;j!=G.vexnum;++j){if(G.arcs[i][j].adj!=10000){edgs[k].pre=i;edgs[k].bak=j;edgs[k].weight=G.arcs[i][j].adj;++k;}}int x,y,m,n;int buf,edf;for(i=0;i!=gra.arcnum;++i)arcvisited[i]=0;for(j=0;j!=G.arcnum;++j){m=10000;for(i=0;i!=G.arcnum;++i){if(edgs[i].weight<m){m=edgs[i].weight;x=edgs[i].pre;y=edgs[i].bak;n=i;}}buf=find(arcvisited,x);edf=find(arcvisited,y);edgs[n].weight=10000;if(buf!=edf){arcvisited[buf]=edf;cout<<"("<<x<<","<<y<<")"<<m;cout<<endl;}}}void main(){algraph gra;MGraph_L G;int i,j,d,g[20][20];char a='a';d=creatMGraph_L(G);creatadj(gra,G);cout<<"*****************************************"<<endl;cout<<"**1.用邻接矩阵存储:*********************"<<endl;cout<<"**2.用邻接表存储:*********************"<<endl;cout<<"**3.PRIM算法实现:*********************"<<endl;cout<<"**4.KRUSCAL算法实现:*********************"<<endl; int s;char y='y';while(y='y'){cout<<"请选择菜单:"<<endl;cin>>s;switch(s){case 1:cout<<"用邻接矩阵存储为:"<<endl;ljjzprint(G);break;case 2:cout<<"用邻接表存储为:"<<endl;adjprint(gra);break;case 3:for(i=0;i!=G.vexnum;++i)for(j=0;j!=G.vexnum;++j)g[i+1][j+1]=G.arcs[i][j].adj;cout<<"PRIM算法最经济的架设方法为:"<<endl;prim(g,d);break;case 4:cout<<"KRUSCAL算法最经济的架设方法为:"<<endl;kruscal_arc(G,gra);break;}cout<<endl<<"是否继续?y/n:";cin>>y;if(y=='n')break;}}。

相关主题