#图# 克鲁斯卡尔 与 并查集
最近有一道数据结构的习题使用到了这两个知识点。简单总结一下。
克鲁斯卡尔算法
可以解决的问题:
- 无向网的最小生成树。
算法思想:
- 贪心。在对问题求解时,总是做出在当前看来是最好的选择。
算法步骤:
- 所有的边按权值从小到大排序。
- 选择权值边中当前最小的权值边。
- 判断已选择的边是否在已选好的边构成的连通分量。
- 若不在,则加入。
(写的太简略了,有点抽象)
在上述算法的第三步中,待选择的边不应在已选择的边构成的连通分量。不得不祭出并查集解决问题。
并查集
可以解决的问题:
- 不相交集合(Disjoint Sets)的合并及查询问题。
算法思想
- 树型的数据结构
算法过程
算法主体分为三个部分初始化、查找、合并。
- 初始化。设置一个数组,所有点存在一个parent数组中并初始化为-1。
- 查找。这里采用优化算法即压缩路径。避免** 退化树**的产生,力求成为查找时的时间复杂度为o(1)!
- 合并算法。
并查集算法简单实现
- 初始化。
int point_num;//parent数组的个数 全局变量
void UFset(int &parent[])
{
for(int i = 0;i < point_num;++i)
{
parent[i] = -1;
}
}
- 查找
int Find(int x)
{
int temp = parent[temp];
while(parent[temp] >= 0)
{
temp = parent[temp]
}
//减少树的高度,优化查找。
while(x != temp)
{
int k = parent[x];
parent[x] = temp;
x = k;
}
return temp;
}
- 合并
//R1 & R2是两个待合并的结点
void Union(int R1,int R2,int &parent[])
{
//求根
int r1 = Find(R1);
int r2 = Find(R2);
int temp = parent[r1]+parent[r2];//两个集合元素之和
//合并至集合元素多的根中
if(parent[r1] > parent[r2])
{
parent[r1] = r2;
parent[r2] = temp;
}
else
{
parent[r2] = r1;
parent[r1] = temp;
}
}