Kruskal算法先将所有的边按权值由小到大排序,然后从无开始(即每个顶点都是一棵子树),每次选取权值最小又不会构成回路的边作为最终最小生成树的一部分。最终能够将多个不连通的子树联合起来构成最小生成树。
时间复杂度为 O(ElogE+V2) 。E为图中的边数,V为图中顶点数。
C++代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef int DATA_TYPE; // 权值为int型
const DATA_TYPE NO_EDGE = 10000000; // 表示没有该边
// 邻接矩阵
struct AdjMatrixGraph
{
vector<vector<DATA_TYPE> > weights;
};
// 边和权值的配对 <<头结点,尾结点>,权值>
typedef pair<vector<int>, DATA_TYPE> PAIR;
int comp(const PAIR &x, const PAIR &y)
{
return x.second < y.second;
}
vector<vector<int> > Kruskal(AdjMatrixGraph graph)
{
vector<vector<int> > MST; // 最小生成树边结果集合
int vertexNum = graph.weights.size(); // 顶点总数
vector<int> setNum; // 每个顶点所属的子树编号
vector<PAIR> edgesAndWeights; // 边和权值配对的向量(便于按值排序)
for (int i = 0; i < vertexNum; ++i)
{
for (int j = 0; j < vertexNum; ++j)
{
if (graph.weights[i][j] > 0 && graph.weights[i][j] < NO_EDGE)
{
// 获取每一条边的信息
edgesAndWeights.push_back(make_pair(vector<int>{i, j}, graph.weights[i][j]));
}
}
setNum.push_back(i); // 初始化每一个顶点都分属不同的子树
}
// 对每一条边按权值升序排序
sort(edgesAndWeights.begin(), edgesAndWeights.end(), comp);
int k = 1; // 当前正在构造第几条边
// 最小生成树总共有vertexNum-1条边
for (vector<PAIR>::iterator mapIter = edgesAndWeights.begin(); mapIter != edgesAndWeights.end(); ++mapIter)
{
int headSet = setNum[mapIter->first[0]]; // 当前边的头结点所属的子树编号
int tailSet = setNum[mapIter->first[1]]; // 当前边的尾结点所属的子树编号
// 如果它们分属不同的子树(即连接之后不构成回路),则选择该边
if (headSet != tailSet)
{
MST.push_back(mapIter->first);
++k;
// 更新顶点的所属子树的编号
for (int i = 0; i < vertexNum; ++i)
{
if (setNum[i] == tailSet)
{
setNum[i] = headSet;
}
}
}
if (k >= vertexNum)
{
break;
}
}
return MST;
}
int main(int argc, char *argv[])
{
// 图邻接矩阵
// 编号从0开始 若不是先转换
AdjMatrixGraph graph;
graph.weights.push_back(vector<DATA_TYPE>{0, 6, 1, 5, NO_EDGE, NO_EDGE});
graph.weights.push_back(vector<DATA_TYPE>{6, 0, 5, NO_EDGE, 3, NO_EDGE});
graph.weights.push_back(vector<DATA_TYPE>{1, 5, 0, 5, 6, 4});
graph.weights.push_back(vector<DATA_TYPE>{5, NO_EDGE, 5, 0, NO_EDGE, 2});
graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, 3, 6, NO_EDGE, 0, 6});
graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, 4, 2, 6, 0});
vector<vector<int> > MST = Kruskal(graph);
for (size_t i = 0; i < MST.size(); ++i)
{
cout <<"边(" << MST[i][0] << " " << MST[i][1] << ") || 权值: " << graph.weights[MST[i][0]][MST[i][1]] << endl;
}
return 0;
}
测试用例图如下:
输出结果:
边(0 2) || 权值: 1
边(5 3) || 权值: 2
边(4 1) || 权值: 3
边(2 5) || 权值: 4
边(2 1) || 权值: 5