利用最小生成树算法解决通信网的总造价最低问题(设计性实验)
1. 需求分析
需求:
若在n个城市之间建通信网络,只需架设n−1条线路即可。如何以最低的经济代价建设这个通信网是一个网的最小生成树问题。
基本要求
以邻接表为存储结构,利用Prim算法或Kruskal算法求网的最小生成树。
- 输入的形式和输入值的范围:图类型,点数,边数,权值
- 输出的形式:打印最小生成树的边
- 程序所能达到的功能:利用Prim算法求图的最小生成树并打印
- 测试数据:
UDG 9 15
A B C D E F G H I
AB11 AF20 BG3 BC45 CD33 BI67 CI56 DI15 DG44 DH14 DE22 EH48 EF44 FG1 GH17
2. 概要设计
- 为了实现程序功能,需要定义图的抽象数据类型。
ADT:图(Graph)
Data:顶点的有穷非空集合和边集合
typedef struct ArcNode{
int adjvex;
int weigth;
struct ArcNode *nextarc;
}ArcNode; //邻接表结构
typedef struct VNode{
VertexType vexdata;
ArcNode *firstarc;
}VNode; //点节点
typedef struct{
VNode *vertices;
int vexnum;
int arcnum;
GraphKind kind[4];
}ALGraph; //图结构
typedef struct{
int first;
int tail;
int weigth;
}edge; // 边结构
Operation:
Graph(V):按照顶点集 VV 初始化图。
addVex(v):在图 G 中添加新顶点 vv。
deleteVex(v):删除图 G 中顶点 vv 及其相关弧。
addEdge(v1,v2):在图 G 中添加弧<v1,v2><v1,v2>,若 G 是无向图,则还需要增添对称弧 <v2,v1><v2,v1>。
deleteEdge(v1,v2):在图 G 中删除弧<v1,v2><v1,v2>,若 G 是无向图,则还需要删除对称弧 <v2,v1><v2,v1>。
DFSTraverse(v):从顶点 vv 开始对图 G 进行深度优先遍历。
BFSTraverse(v):从顶点 vv 开始对图 G 进行广度优先遍历。
3. 具体代码
- 图.h:
#define VertexType char
#define GraphKind char
#define TRUE 1
#define FALSE 0
typedef struct ArcNode{
int adjvex;
int weigth; //权值
struct ArcNode *nextarc;
}ArcNode; //邻接表结构
typedef struct VNode{
VertexType vexdata;
ArcNode *firstarc;
}VNode; //点节点
typedef struct{
VNode *vertices;
int vexnum;
int arcnum;
GraphKind kind[4];
}ALGraph; //图结构
typedef struct{
int first;//头
int tail;//尾
int weigth;
}edge; // 边结构
int LocateVex(ALGraph *a,char ch) //查找节点
{
int i = 0;
for(;i < a->vexnum;++i)
{
if(a->vertices[i].vexdata == ch)
{
return i;
}
}
exit(-1);
}
void CreateGraph(ALGraph *a,FILE *r) //创建图
{
char ch;
fscanf(r,"%s",&a->kind[0]);
fscanf(r,"%c",&ch);
fscanf(r,"%d %d",&a->vexnum,&a->arcnum);
fscanf(r,"%c",&ch);
a->vertices = (VNode*)malloc(a->vexnum * sizeof(VNode));
int i = 0;
for(;i < a->vexnum;++i)
{
fscanf(r,"%c",&a->vertices[i].vexdata);
fscanf(r,"%c",&ch);
a->vertices[i].firstarc = NULL;
}
i = 0;
for(;i < a->arcnum;++i)
{
char sv,tv;
int we;
fscanf(r,"%c%c%d",&sv,&tv,&we);
fscanf(r,"%c",&ch);
int j = LocateVex(a,sv);
int k = LocateVex(a,tv);
ArcNode *p = (ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = k;
p->weigth = we;
p->nextarc = a->vertices[j].firstarc;
a->vertices[j].firstarc = p;
if(a->kind[0] == 'U'&&a->kind[1] == 'D')
{
ArcNode *q = (ArcNode*)malloc(sizeof(ArcNode));
q->adjvex = j;
q->weigth = we;
q->nextarc = a->vertices[k].firstarc;
a->vertices[k].firstarc = q;
}
}
}
void MiniSpanTree_PRIM(ALGraph a,edge *e) //Prim算法求最小生成树
{
//U为最小生成树的顶点集,TE为最小生成树的边集。
int U[a.vexnum],number = 0,judge[a.vexnum];//U数组装顶点,judge做判断顶点
int n = 0;//用于for循环
for(;n < a.vexnum;n++)//遍历所有judge,全部赋值为-1
{
judge[n] = -1;
}
U[number++] = 0;//u[0]=0,number++
judge[U[number-1]] = 0;//judge[0]=0
for(;number <= a.vexnum;number++)//number从1开始 //每次循环返回一个边结构,一共返回
{
edge j;//创建一个边结构
j.tail = -1;//边的尾先设为空
int i = 0;//用于for循环
for(;i < number;i++)//遍历所有节点
{
ArcNode *p = a.vertices[U[i]].firstarc;//用于for循环 , U中的所有节点
for(;p != NULL;p = p->nextarc)//遍历该节点得所有邻接节点
{
if(judge[p->adjvex] == -1)//如果未进入U数组
{
j.tail = p->adjvex;//边尾就是这个邻接节点
j.first = U[i];//边头部就是这个节点
j.weigth = p->weigth;//边的权值
break;
}
}
if(j.tail != -1)//如果边已经有主了,跳出for循环
{
break;
}
}
i = 0;//用于for循环
for(;i < number;i++)//遍历所有节点
{
ArcNode *p = a.vertices[U[i]].firstarc;//用于for循环, U中的所有节点
for(;p != NULL;p = p->nextarc)遍历该节点得所有邻接节点
{
if(judge[p->adjvex] == -1&&p->weigth <= j.weigth)//更新节点,如果有权值更少的
{
j.tail = p->adjvex;//
j.first = U[i];
j.weigth = p->weigth;
}
}
}
U[number] = j.tail;
judge[U[number]] = 0;
e[number-1] = j;//把j放入
}
}
- 主程序.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"图.h"
//使用算法为prim算法
int main()
{
FILE *r,*w;
printf("请将数据放入文件'data.txt'中。(放好请按ENTER键继续)");
getchar();
if((r = fopen("data.txt","r")) == NULL)
{
exit(-1);
}
if((w = fopen("result.txt","w")) == NULL)
{
exit(-1);
}
ALGraph graph;
CreateGraph(&graph,r);
edge e[graph.vexnum - 1];
MiniSpanTree_PRIM(graph,e);
//MiniSpanTree_PRIM(&graph,e);
fprintf(w,"要架设的路线分别是:\n");
int i = 0;
for(;i < (graph.vexnum - 1);i++)
{
fprintf(w,"%c%c ",graph.vertices[e[i].first].vexdata,graph.vertices[e[i].tail].vexdata);
}
printf("结果已放入文件'result.txt'中。");
return 0;
}
4. 相关数据
- data.txt
UDG 7 12
A B C D E F G
AB2 AC4 AD1 BD3 CD2 BE10 DE7 CF5 DF8 DG4 EG6 FG1
- 初始图
- 最小生成树