基本思想:(加边)
1.设无向连通网为G=(V, E),令G的最小生成树为T=(U, TE),其初态为U=V,TE={ },
2.然后,按照边的权值由小到大的顺序,考察G的边集E中的各条边。
2.1若被考察的边的两个顶点属于T的两个不同的连通分量,则将此边作为最小生成树的边加入到T中,同时把两个连通分量连接为一个连通分量;
2.2若被考察边的两个顶点属于同一个连通分量,则舍去此边,以免造成回路,
2.3如此下去,当T中的连通分量个数为1时,此连通分量便为G的一棵最小生成树。
伪代码:
算法:Kruskal算法
输入:无向连通图G={V,E}
输出:最小生成树T={U,TE}
1. 初始化:U=V; TE={};
2. 循环直到T中的连通分量个数为1
2.1 在E中寻找最短边(u,v);
2.2 如果顶点u、v位于T的两个不同连通分量,则
2.2.1 将边(u,v)并入TE;
2.2.2 将这两个连通分量合并为一个;
2.3 在E中标记边(u,v),使得(u,v)不参加后续最短边的选取;
代码实现:
struct EdgeType //定义边集数组的元素类型
{
int from, to, weight; //假设权值为整数
};
const int MaxVertex = 10; //图中最多顶点数
const int MaxEdge = 100; //图中最多边数
template //定义模板类
class EdgeGraph
{
public:
EdgeGraph(DataType a[], int n, int e);//构造函数,生成n个顶点e条边的连通图
~EdgeGraph(); //析构函数
void Kruskal(); //Kruskal算法求最小生成树
private:
int FindRoot(int parent[], int v);//求顶点v所在集合的根
DataType vertex[MaxVertex];//存储顶点的一维数组
EdgeType edge[MaxEdge];//存储边的边集数组
int vertexNum, edgeNum;
};
template<T>
EdgeGraph::EdgeGraph(DataType a[], int n, int e)
{
int i, j, k, w;
vertexNum = n; edgeNum = e;
for (i = 0; i < vertexNum; i++)
vertex[i] = a[i];
for (k = 0; k < edgeNum; k++)
{
cout << "请输入边依附的两个顶点的编号,以及边上的权值:";
cin >> i >> j >> w; //输入边依附的两个顶点的编号
edge[k].from = i; edge[k].to = j; edge[k].weight = w;
}
}
template<T>
EdgeGraph::~EdgeGraph(){}
template<T>
void EdgeGraph :: Kruskal()
{
int num = 0, i, vex1, vex2;
int parent[vertexNum]; //双亲表示法存储并查集
for (i = 0; i < vertexNum; i++)
parent[i] = -1; //初始化n个连通分量
for (num = 0, i = 0; num < vertexNum - 1; i++) //依次考察最短边
{
vex1 = FindRoot(parent, edge[i].from);
vex2 = FindRoot(parent, edge[i].to);
if (vex1 != vex2){ //位于不同的集合
cout << "(" << edge[i].from << "," << edge[i].to << ")" << edge[i].weight << endl;
parent[vex2] = vex1; //合并集合
num++;
}
}
}
template<T>
int EdgeGraph :: FindRoot(int parent[ ], int v) //求顶点v所在集合的根
{
int t = v;
while (parent[t] > -1) //求顶点t的双亲一直到根
t = parent[t];
return t;
}