图的最小生成树,就是基于图,假设其有n的顶点,那么就要构建一颗连通树,使其各边权重和最小。最小生成树的实现算法主要有两种:Prim算法和Kruskal算法。Prim算法在前面已经介绍过,本文着重介绍Kruskal算法及其实现,其中图的实现以及相关操作,采用前面博文C++ 图的实现中的实现方式,由于本文重点在于Kruskal算法的实现,所有就不在图的构建以及相关操作中过多赘述。
对于Kruskal算法,维基的解释其实已经很详细了,算法思想很好理解,不多说明,直接看实现。
/*
*无向图查找最小树:Kruskal算法
*不断找最小值,在不形成环的前提下,加入边
*----- By F8Master
*/
#include "Graphmtx.h"
#include<iostream>
#include<vector>
using namespace std;
struct EdgeByInt
{
int v1,v2;
EdgeByInt(){};
EdgeByInt (int v11,int v22){
v1 = v11;
v2 = v22;
}
};
template<class T ,class E>
void Kruskal(Graphmtx<T,E> &G,vector<EdgeByInt> &v)//参数分别为图,存储最小树的边的vector
{
int numV = G.NumberOfVertices();//获得顶点数
int *setV = new int[numV];
for(int i = 0;i<numV;i++)//初始时候每个点自成一组
{
setV[i]=i;
}
v.clear();//vector清空
int j = 1;//用于记录确定的边的数目
while(j<numV )
{
E min = INF;
int left = -1;
int right = -1;
for(int m = 0;m<numV;m++)//首先找到现存的最小值
{
for (int n = m+1;n<numV;n++)
{
if (G.getWeight(m,n)<min)
{
min = G.getWeight(m,n);
left = m;
right = n;
}
}
}
G.removeEdge(left,right);//删除边
if(setV[left]!=setV[right])//如果不在同一个集合,也就不形成回路
{
EdgeByInt temp(left,right);
v.push_back(temp);
int SetofLeft = setV[left];
int SetofRight = setV[right];
for(int k=0;k<numV;k++)//更新集合分组信息
{
if(setV[k]==SetofRight)
setV[k] = SetofLeft;
}
j++;
}
}
};
template <class T ,class E>
void printMinTree(Graphmtx<T,E> & G,vector<EdgeByInt> &v)
{
int size = v.size();
EdgeByInt temp;
int left,right;
for(int i = 0;i<size;i++)
{
temp = v[i];
left = v[i].v1;
right = v[i].v2;
cout<<"("<<G.getValue(left)<<" , "<<G.getValue(right)<<")"<<endl;
}
};
//测试程序
void test_Kruskal()
{
Graphmtx<char,int> G ;
G.inputGraph();
vector<EdgeByInt> v(G.NumberOfEdges()-1);
Kruskal(G,v);
printMinTree(G,v);
}
看两组实现的例子: