欢迎收看今天的算法课堂,今天的主要内容有 并 查 集 和 并 查 集 和 并 查 集
首先是并查集所能解决的主要问题——连接问题和路径问题,其思想是将所相连的点连成树,用一个数组记录每一个节点的前驱,如果是单个的点,前驱就是自己,方便并查的操作
并查集主要是两种操作,并(union)和查(find)
-
union & find
并主要是指将两个节点连接在一起或是将两棵树连接在一起,如果是单个的节点与一棵树或是一个节点连接,直接改变这个节点的前驱标记即可,如果是两棵树相连,那么需要遍历到树的根再进行连接——尽量减少树的深度,方便树的遍历具体方法如下——
int find_root(int p)
{
//查找根节点
while(p != parent[p])
p = parent[p];
return p;
}
bool isConnected(int a, int b)
{
//判断ab节点是否相连
return find_root(a) == find_root(b);
}
void unionElements(int a, int b)
{
int roota = find_root(a),rootb = find_root(b);
if(roota==rootb) return;
parent[roota] = rootb;
}
- 并查集的优化
优化的角度从减少树的高度的角度进行,假如我们一直将层数高的树和一棵层数底的树进行union,那么最终的树的高度会不断增加,不过在实际操作中,由于求树的层数要用dfs较为耗时,所以经常采用每棵树元素的个数进行比较,将元素少的树加在元素多的树上
所以在代码的层面上,只需多一步求每棵树元素的个数——
void unionElements(int a, int b)
{
int roota = find_root(a),rootb = find_root(b);
//遍历一遍各个节点的根节点看哪棵树的元素多
int sz_a=0,sz_b=0;
for(int i=0; i<cnt; i++)
{
find_root(i);
if(i==roota)
sz_a++;
if(i==rootb)
sz_b++;
}
if(roota==rootb)
return;
if(sz_a>sz_b)
parent[rootb] = roota;
else
parent[roota] = rootb;
}
- 并查集的路径压缩
在求4的根节点的时候,就可以采取parent[p] = parent[parent[p]],这样就跳过了一步,那么如果提前到了根节点咋整呢?由于并查集中开始时本身的parent[p] = p,所以就会在原地打转,不影响