图论算法-最小生成树
在一个无向图中找出一颗最小生成树(minimum spanning tree),这个问题对有向图也是有意义的,不过找起来更困难。最小生成树存在当且仅当图是连通的。在最小生成树中边的条数为。
Prim算法
在每一步,都要把一个节点当作根并往上边加。在算法的任一时刻,我们都可以看到一个已经添加到树上的顶点集,而其余顶点尚未加到这棵树中,此时,算法在每一阶段都可以通过选择边,使得的值是所有在树上但不在树上的边值中的最小者,而找出一个新的顶点并把它添加到这棵树中。
代码
这里使用的邻接矩阵。
void Prim(Graph g)
{
VertexType adjver[VERNUM];
WeightType lowcost[VERNUM];
int i, j, k;
WeightType min;
// 初始化,一开始生产树中只有开始的顶点
// 这里开始的顶点的编号为 0
for (i = 0; i < g->vernum; i++)
{
lowcost[i] = g->arc[0][i];
adjver[i] = 0;
}
for (i = 1; i < g->vernum; i++)
{
// 在已生成树的顶点中查找权值最小的邻接点的边
k = 0;
min = INFINITY;
for (j = 1; j < g->vernum; j++)
if (lowcost[j] != 0 && lowcost[j] < min)
{
min = lowcost[j];
k = j;
}
// 输出新增加的顶点
printf("(%d, %d)\n", adjver[k] + 1, k + 1);
lowcost[k] = 0; // 标记添加到树中的顶点不再使用
// 更新图中顶点邻接点的权值及顶点
for (j = 1; j < g->vernum; j++)
if (lowcost[j] != 0 && g->arc[k][j] < lowcost[j])
{
adjver[j] = k;
lowcost[j] = g->arc[k][j];
}
}
}
输入/输出
Input vernum: 7
Input arcnum: 12
1 2 2
1 3 4
1 4 1
2 4 3
2 5 10
3 4 2
3 6 5
4 5 7
4 6 8
4 7 4
5 7 6
6 7 1
Prim's algorithm minmum spanning tree:
(1, 4)
(1, 2)
(4, 3)
(4, 7)
(7, 6)
(7, 5)
请按任意键继续. . .
Kruskal算法
第二种贪婪策略是连续地按照最小边的权选择边,并且当所选的边不产生圈时就把它作为取定的边。
代码1
图使用邻接矩阵表示。
void Kruskal(Graph G)
{
int i, vs1, vs2;
VertexType v1, v2;
// 辅助数组
VertexType head; // 边的始点
VertexType tail; // 边的终点
ArcType lowcost; // 边的权值
int Vexset[VerNum]; // 实际上是一个并查集(不相交集)
// 按图中的边的权值大小排序,存储到前三个数组中
Sort(Edge); // 将前3个数组中的元素按权值从小到大排序
for(i = 0; i < G->vernum; i++)
{
// 获取边始点和终点的下标
v1 = LocateVex(G, head[i]);
v2 = LocateVex(G, tail[i]);
// 获取两个顶点所在的连通分量
vs1 = Vexset[v1];
vs2 = Vexset[v2];
if(vs1 != vs2)
{
// 将新添加的边打印输出
printf("(%d, %d)\n", head[i], tail[i]);
// 合并 vs1 和 vs2 两个分量,将两个集合统一
for(j = 0; j < G->vernum; j++)
if(Vexset[j] == vs2) // 集合编号为 vs2 的都改为 vs1
Vexset[j] = vs1;
}
}
}
代码来自严蔚敏《数据结构(C语言版)(第2版)》,实际上这个代码并没有交代清楚其背后的运行,还有阉割了两个数据结构的介绍。
代码2
void Kruskal(Graph G)
{
int EdgeAccepted;
DisjSet S; // 并查集(不相交集)
PriorityQueue H; // 优先队列
Vertex U, V;
SetType Uset, Vset; // 并查集根的数据类型
Edge E;
// 初始化并查集,一开始每个顶点都在一个单独的集合中
Intialize(S);
// 构造优先队列(实际上就是对边的权值进行排序)
ReadGraphIntoHeapArray(G, H); // 将每条边放到优先队列中(此时未排序)
BuildHeap(H); // 对优先队列进行“排序”
// 最小生成树中边的个数是顶点的个数减1
EdgeAccepted = 0;
while(EdgeAccepted < NumVertex - 1)
{
// 从优先队列取出权值为最小值的边并删除
// E中有两个点,始点和终点,E = (U, V)
E = DeleteMin(H);
// 查找两个顶点所在的集合
Uset = Find(U, S);
Vset = Find(V, S);
if(Uset != Vset)
{
// 输出生产的边
printf("(%d, %d)\n", U, V);
EdgeAccepted++;
// 合并两个集合
SetUnion(S, Uset, Vset);
}
}
}
代码来自Mark Allen Weiss的《数据结构与算法分析 C语言描述》。
来源:CSDN
作者:帅到没朋友fx
链接:https://blog.csdn.net/u011714517/article/details/104302639