最小生成树算法——kruskal
Kruskal
kruskal与prim不同,是基于边去构造最小生成树,所以适用于边比较少的稀疏图。
kruskal需要边的集合,我们称其为边集数组。边集数组按从小到大的顺序排序,方便构造最小生成树。
边集数组
结构体1
2
3
4
5struct edge {
int begin, end, weight;
bool operator<(edge const& rhs)
{return this->weight < rhs.weight;}
}edges[maxsize * (maxsize - 1)];
边集数组构造函数1
2
3
4
5
6
7
8
9
10
11
12void get_edges_set()
{
int a = 0;
for (int i = 0; i < nume; i++)
{
cin >> u >> v >> w;
edges[a].begin = u - 'A';
edges[a].end = v - 'A';
edges[a++].weight = w;
}
sort(edges, edges + a);
}
构造最小生成树
边集数组构造好,vector中根据权值从小到大排序。我们沿着下标选择begin和end连线来构造最小生成树,但是,在连接过程中可能出现成环的现象,这是由于父节点重复了,孩子想与父节点连在一起或是孩子想连在一起而造成的一种严重错误。
我们可以通过并查集来避开成环情况。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18int findset(int x)
{
return (fa[x] == x) ? x : findset(fa[x]);
}
void Union(int b, int e)
{
int bb = findset(b);
int ee = findset(e);
if (bb != ee)
fa[bb] = ee;
}
void init()
{
for(int i = 0; i < maxsize; i++)
fa[i] = i;
}
Kruskal1
2
3
4
5
6
7
8
9
10
11
12
13void kruskal(vector<pair<int, int>>& ET)
{
for (int i = 0; i < nume; i++)
{
int uu = findset(edges[i].begin);
int vv = findset(edges[i].end);
if (uu != vv)
{
Union(edges[i].begin, edges[i].end);
ET.push_back(make_pair(edges[i].begin, edges[i].end));
}
}
}
实现代码
1 |
|
时间复杂度
Tn=O(e)·O(sort)+O(e)·α(v)
α是阿克曼的反函数,近乎常数(不超过5)
因此Tn=O(eloge);