最小生成树
就像几个村庄都不相通, 要修路, 怎么修, 这个花的钱最少, 这种最优选择就是最小生成树
设G = (V, E)是无向连通图(V是结点集, E是边集),相对于村庄例子,V就是那些村庄的集合,E就是村庄之间路的集合
设T = (U, TE)是最小生成树, U是结点集,TE是边集
Prim算法的思想
- 首先在V集合中任意选择一个村庄作为起始点i,将i点并入U集合中,然后在找一个修路到i村庄最便宜的j村庄并入集合TE中(在所有i∈U, j∈V-U中找一条代价最小的边(i,j))
- 重复第一步的操作
设数组adjvex[n]表示候选最短边的领接点
设数组lowcast[n]表示权值
其值如下,含义是候选最短边(i,j)的权值为w,其中i∈V-U , j∈U
adjvex[i] = j
lowcost[i] = w
介绍了这么多抽象概念,还是看图理解一下Prim算法的流程
C语言实现
#include<stdio.h>
#define MaxSize 100
struct MGraph {
int vertex[MaxSize];// 定义存放顶点的一维数组
int edge[MaxSize][MaxSize]; // 存放边的二维数组
int vertexNum, edgeNum;
};
int MinEdge(int *lowcost, int num) {
int min = 9999;
int index = -1;
for(int i = 0; i < num; i++) {
if(lowcost[i] < min && lowcost[i] != 0) {
min = lowcost[i];
index = i;
}
}
return index;
}
void Prim(MGraph *G, int v) {// 从顶点V出发
int i, j, k;
int adjvex[MaxSize], lowcost[MaxSize];
for (i = 0; i < G -> vertexNum; i++) {// 初始化
lowcost[i] = G -> edge[v][i];
adjvex[i] = v;
}
lowcost[v] = 0; /* 将顶点v加入集合*/
for (k = 1; k < G -> vertexNum; k++) {
j = MinEdge(lowcost, G -> vertexNum);// 寻找最短边的领接点
printf("(%d, %d)%d ", j, adjvex[j], lowcost[j]);// 输出最短边(j, i)及其权值
lowcost[j] = 0; /* 将顶点j加入集合*/
for (i = 0; i < G ->vertexNum; i++) { /* 更新 */
if (G -> edge[i][j] < lowcost[i]) {
lowcost[i] = G -> edge[i][j];
adjvex[i] = j;
}
}
}
}
int main() {
MGraph g;
MGraph *G = &g;
G -> vertexNum = 6;//6个顶点
G -> edgeNum = 9;// 9条边
for(int i = 0; i < 6; i++)
for(int j = 0; j < 6; j++)
G -> edge[i][j] = 9999;// 无限大
G -> edge[0][1] = 34; G -> edge[1][0] = 34;
G -> edge[0][2] = 46; G -> edge[2][0] = 46;
G -> edge[0][5] = 19; G -> edge[5][0] = 19;
G -> edge[1][4] = 12; G -> edge[4][1] = 12;
G -> edge[2][3] = 17; G -> edge[3][2] = 17;
G -> edge[2][5] = 25; G -> edge[5][2] = 25;
G -> edge[3][4] = 38; G -> edge[4][3] = 38;
G -> edge[3][5] = 25; G -> edge[5][3] = 25;
G -> edge[4][5] = 26; G -> edge[5][4] = 26;
Prim(G, 0);
}
参考书籍:数据结构(王红德 皮德常)