克鲁斯卡尔(Kruskal)算法
- 克鲁斯卡尔算法的基本思想是:设一个有n个顶点的连通网络G={V,E},
(1)先构造一个包括全部n个顶点和0条边的森林F={T0,T1,…,Tn-1},
(2)以后每一步向下中加入一条边(v,u),它应是所依附的两个顶点v和u分别在森林F的两棵不同的树上的所有边中具有最小权值的边。由于这条边的加入,使F中的某两棵树合并为一棵,树的棵数减一。
(3)如此,经过n-1步,最终得到一棵有n-1条边且各边权值总和达到最小的生成树,即最小生成树。
- 例如,对于图7-18(a)所示的连通网络,图7-19中(a)~(f)给出了按克鲁斯卡尔算法生成最小生成树的过程。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200507132316109.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNDEzNDAz,size_16,color_FFFFFF,t_70)
- 在克鲁斯卡尔算法中,利用最小堆来存放连通网络中的边,堆中每个元素代表连通网络中的一条边,它由三个域组成:adjvex1、adjvex2和 weight。
其中adjvex1和adjvex2存储该边所依附的两个顶点的序号,weight存储边上的权值。
利用并查集存放所有连通分量,同一个连通分量的顶点组成并查集的一个子集(等价类)。
- 克鲁斯卡尔算法步骤如下。
1)初始化,在并查集中,连通网络的每一个顶点独立成一个等价类,连通网络的所有的边建立最小堆,最小生成树T中没有任何边,T中边的条数计数器i为0。
2)如果T中边的条数计数器i等于顶点数减1,则算法结束;否则继续步骤3)。
3)选取堆顶元素代表的边(v,u),同时调整堆。
4)利用并查集的运算检查依附于边(v,u)的两个顶点v和u是否在同一个连通分量(即并查集的同一个子集合)上,如果是则转步骤2);否则继续步骤5)。
5)将边(v,u)加入到最小生成树T中,同时将这两个顶点所在的连通分量合并成一个连通分量(即并查集中的相应两个子集合并成一个子集),继续步骤2)。
代码实现
Kruskal算法代码
template<class ElemType,class WeightType> void MiniSpanTreeKruskal(const AdjMatrixUndirGraph<ElemType,WeightType> &g)
{
int count,VexNum=g.GetVexNum();
KruskalEdge<ElemType,WeightType> KEdge;
MinHeap<KruskalEdge<ElemType,WeightType> > ha(g.GetArcNum());
ElemType *kVex,v1,v2;
kVex=new ElemType[VexNum];
for(int i=0; i<VexNum; i++)
g.GetElem(i,kVex[i]);
UFSets<ElemType> f(kVex,VexNum);
for(int v=0; v<VexNum; v++)
for(int u=g.FirstAdjVex(v); u>=0; u=g.NextAdjVex(v,u))
if(v<u)
{
g.GetElem(v,v1);
g.GetElem(u,v2);
KEdge.vertex1=v1;
KEdge.vertex2=v2;
KEdge.weight=g.GetWeight(v,u);
ha.Insert(KEdge);
}
count=0;
cout<<"Kruskal最小生成树需要连接一下边:"<<endl;
while(count<VexNum-1)
{
ha.DeleteTop(KEdge);
v1=KEdge.vertex1;
v2=KEdge.vertex2;
if(f.Differ(v1,v2))
{
cout<<"edge:( "<<v1<<" , "<<v2<<" ) weight:"<<KEdge.weight<<endl;
f.Union(v1,v2);
count++;
}
}
}
辅助代码
边类
template<class ElemType,class WeightType> class KruskalEdge
{
public:
ElemType vertex1,vertex2;
WeightType weight;
KruskalEdge(ElemType v1,ElemType v2,WeightType w);
KruskalEdge() {
}
KruskalEdge<ElemType,WeightType>& operator=(const KruskalEdge<ElemType,WeightType> &Ed);
bool operator<=(const KruskalEdge<ElemType,WeightType> &Ed);
bool operator>(const KruskalEdge<ElemType,WeightType> &Ed);
friend ostream& operator<<(ostream &out,const KruskalEdge<ElemType,WeightType> &Ed)
{
out<<"( "<<Ed.vertex1<<" , "<<Ed.vertex2<<" ) weight:"<<Ed.weight;
return out;
}
};
template<class ElemType,class WeightType> KruskalEdge<ElemType,WeightType>::
KruskalEdge(ElemType v1,ElemType v2,WeightType w)
{
vertex1=v1;
vertex2=v2;
weight=w;
}
template<class