查集就是维护了几个动态的集合,集合中的每一个元素都标记了一个父节点,同一个集合的代表是相同的。当一个元素的父节点就是他本身时,它就是该集合的代表。
并查集有三种操作:
1. init(n):用于初始化集合,将每个元素的父节点设置为他本身。即表示当前一个元素为一个集合,互相没有联系
2. find(x):返回x所在集合的代表
3. unite(x,y):合并x,和y所在的集合。即把y的代表设置为x所在集合的代表
根据并查集判断两个元素是否有联系,只需判断他们是否在同一个集合里即可,也就是判断他们的代表是不是同一个
>>初始化
// 初始化n个元素 void init(int n) { for (int i = 1; i <= n; i++) { par[i] = i; rank[i] = 0; } }
>>查询
//递归实现 int find(int x) { if (par[x]!=x) return find(par[x]); else return x; //或者用return x == father[x] ? x: father[x] = find(father[x]); } //非递归路径压缩操作 int find(int x) { int r = x; while(r!=par[r]) r = par[r]; //路径压缩 int i = x, j; while(i!=r) { j = par[i]; //用j暂存par[i]的父节点 par[i] = r; //par[i]指向根节点 i = j; //i移到父节点 } return r; }
>>合并
//合并x和y所在的集合 void unite(int x, int y) { x = find(x); y = find(y); //将x和y的根分别赋值给x和y if (x==y) return; //如果x于y的根相同,则不必合并 if (rank[x]<rank[y]) //合并时如果两棵树的高度不同,则将rank小的连到rank到的上面 par[x] = y; else { par[y] = x; if (rank[x]==rank[y]) rank[x]++; //如果相同,则最高的高度合并之后需要在原来的基础上+1 } }
参考自:
https://www.cnblogs.com/frankM/p/4399556.html
https://www.cnblogs.com/52dxer/p/10470004.html
https://www.cnblogs.com/sr1993/p/3697783.html
http://www.cnblogs.com/tanhehe/archive/2013/01/28/2883506.html
https://blog.csdn.net/zchahaha/article/details/51123557