目录
1.生成树的概念
(1)子图包含原图全部节点,子图为连通图
(2)在(1)的前提下使子图尽可能的少包含原图中的边
满足以上两点的子图称为原图的生成树。生成树必定包含且仅包含原图的 n - 1 条边
最小生成树:在图的所有生成树中,n - 1 条边上权值和最小的树
2.普里姆算法最小生成树(Prim)
G = (V, E)为一连通网。V:网中所有点的集合;E:网中所有带权边的集合
设两个新的集合U,T:
(1)U:存放G的最小生成树的节点
(2)T:存放G的最小生成树的边
Prim算法构造最小生成树步骤:
(1)令集合U的初值为 U = { U1 }(假设构造最小生成树从U1出发)
(2)令集合T的初值为 T = { }
(3)从所有 u U,v V - U的边中选择具有最小权值的边(u,v),将节点 v 加入 U,边(u,v)加入 T
(4)不断重复步骤(3),直至 U = V 时最小生成树构造完毕。
以上图为例:
3.源代码示例
3.1Prim算法
实现此算法需要设置两个辅助数组:lowcost、colsevertex
(1)lowcost:保存集合 V - U 中各节点与集合 U 中各节点构成的边中具有最小权值的边的权值。若lowcost [ i ] = 0,表明下标 为 i 的节点已加入集合 U 中
(2)closevertex:保存依附于最小权值边的在集合 U 中的节点
#include <stdio.h>
#include <stdlib.h>
#define INFINITY 10000 /* 假定边上权值无穷大时为10000 */
#define MAX_VERTEX_NUM 100 /* 图中最大节点数 */
typedef char VertexType; /* 顶点类型设置为字符型 */
typedef int EdgeType; /* 边上权值类型设置为整型 */
typedef struct /* 边表节点 */
{
VertexType vex[MAX_VERTEX_NUM]; /* 图中节点 */
EdgeType edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; /* 邻接矩阵 */
int vexnum; /* 节点的数目 */
int edgenum; /* 边的数目 */
}MGraph;
void CreateMG(MGraph * MG); /* 邻接矩阵法创建无向图 */
void PrintMG(MGraph MG); /* 邻接矩阵形式输出图MG */
void MiniSpanTree_Prim(MGraph MG); /* Prim算法建立最小生成树 */
void locateVex(MGraph MG, VertexType vex, int * index);
/* 定位节点vex的下标并赋给index */
int main(void)
{
MGraph g;
CreateMG(&g);
printf("------------------------------\n");
printf("vexnum = %d ; edgenum = %d\n", g.vexnum, g.edgenum);
printf("------------------------------\n");
PrintMG(g);
printf("------------------------------\n");
MiniSpanTree_Prim(g);
return 0;
}
void CreateMG(MGraph * MG)
{
int i = 0, j, k, w; /* w:权值 */
char ch;
printf("请依次输入顶点数、边数:");
scanf("%d %d", &(MG->vexnum), &(MG->edgenum));
printf("请依次输入顶点(以回车结束输入):");
getchar();
while ((ch = getchar()) != '\n') /* 输入顶点信息 */
MG->vex[i++] = ch;
for (i = 0; i < MG->vexnum; i++) /* 初始化邻接矩阵 */
for (j = 0; j < MG->vexnum; j++)
MG->edges[i][j] = INFINITY;
printf("顶点 | 下标\n");
for (i = 0; i < MG->vexnum; i++) /* 显示图中顶点及其对应下标 */
{
printf("%3c%6d\n", MG->vex[i], i);
}
printf("请输入每条边对应的两个顶点下标及边的权值(格式:i j w):\n");
for (k = 0; k < MG->edgenum; k++) /* 建立邻接矩阵 */
{
scanf("\n%d%d%d", &i, &j, &w); /* 输入边的两个节点及权值 */
MG->edges[i][j] = w; /* 将矩阵对应位置元素置为权值 */
MG->edges[j][i] = w;
}
}
void PrintMG(MGraph MG)
{
int i, j;
for (i = 0; i < MG.vexnum; i++) /* 输出邻接矩阵 */
{
for (j = 0; j < MG.vexnum; j++)
{
if (MG.edges[i][j] == INFINITY) /* 节点不连通时,输出'#'代表无穷大 */
printf("%3c", '#');
else /* 节点连通时,输出边上权值 */
printf("%3d", MG.edges[i][j]);
}
printf("\n");
}
}
void MiniSpanTree_Prim(MGraph MG)
{
int i, j, k, index, mincost; /* index:开始节点下标 */
int lowcost[MG.vexnum], closevertex[MG.vexnum];
char ch; /* 最小生成树的开始节点 */
printf("请输入开始节点:");
getchar();
scanf("%c", &ch);
locateVex(MG, ch, &index); /* 求出开始节点的下标并赋给index */
lowcost[index] = 0;
closevertex[0] = index; /* 将开始节点加入集合U */
for (i = 0; i < MG.vexnum; i++) /* 辅助数组初始化 */
if (i != index)
lowcost[i] = MG.edges[index][i];
for (i = 1; i < MG.vexnum; i++)
{
mincost = INFINITY;
for (j = 0; j < MG.vexnum; j++)
{
if (lowcost[j] < mincost && lowcost[j] != 0)
{
mincost = lowcost[j]; /* 最小权值 */
k = j; /* 权值最小的节点下标 */
}
}
/* 输出当前顶点边中权值最小的边 */
printf("顶点:%c ;权值:%d\n", MG.vex[k], mincost);
lowcost[k] = 0; /* 将当前顶点的权值设为0,表示此顶点已经完成任务 */
closevertex[i] = k; /* 与权值最小边关联的节点下标并入集合U */
for (j = 0; j < MG.vexnum; j++) /* 更新节点与其他节点之间的最小权值和集合U */
{
if (MG.edges[k][j] < lowcost[j])
lowcost[j] = MG.edges[k][j];
}
}
}
void locateVex(MGraph MG, VertexType vex, int * index)
{
int i;
for (i = 0; i < MG.vexnum; i++)
{
if (MG.vex[i] == vex)
{
*index = i;
return;
}
}
printf("节点定位失败!\n");
}