克鲁斯卡尔方法(Kruskal):不断将最小的但不会构成回路的边并入树。
示例如下:
判断是否构成回路要用到并查集,并查集可快速查找要并入的边与当前的树是否为同一集合(是否在同一棵树中),若为同一集合(在同一棵树中)则会构成回路。
并查集的实现方式为:并查集v[a]用来存放a的双亲结点,当a ==v[a]时为根节点,可通过语句"while(a != v[a]) a = v[a];"从a出发最终得到的a',为最初的a的根节点。当两个结点的根节点相同时a ==b,则产生回路。
C代码如下:
struct Road{ //简易的定义一条边
int a, b; //一条边的两个顶点
int w; //边的权值
};
Road road[m];
int v[maxSize] = {0}; //定义并查集数组
int getRoot(int a) //在并查集中找根节点的函数
{
while(a != v[a]) a = v[a]; //自己为自己双亲时,为根节点
return a;
}
void Kruskal(MGraph g, int &sum, Road road[]) //克鲁斯卡尔方法
{
int i, a, b;
sum = 0;
for(i = 0; i < g.n; ++i)
v[i] = i; //各自为根节点(一棵树)
sort(road, g.e); //对所有边进行排序
for(i = 0; i < g.e; ++i){ //排过序的边依次判断
a = getRoot(road[i].a);
b = getRoot(road[i].b);
if(a != b){ //不同根时,将该边并入(此时不会形成回路)
v[a] = b; // b成为a的双亲结点
sum += road[i].w;
}
}
}