union-find算法
动态连通性
问题描述:输入一列整数对,其中每个整数表示一个某种类型的对象,一对整数p、q可理解为p和q是相连的,假设相连是一种等价关系,其具有:
- 自反性:p和p是相连的
- 对称性:如果p和q相连,那么q和p也是相连的
- 传递性:如果p和q是相连的且q和r是相连的,那么p和r也是相连的
等价关系能够将对象分为多个等价类,当且仅当两个对象相连时他们才属于同一个等价类。连通性问题要求能够判断给定的整数对p、q是否相连;
union-find算法API
| public class UF | ||
|---|---|---|
| UF(int N) | 以整数标识(0~N-1)初始化N个触点 | |
| void | union(int p, int q) | 在p和q之间添加一条连接 |
| int | find(int p) | p所在分量的标识符 |
| boolean | connected(int p, int q) | 如果p和q存在于同一个分量中则返回true |
| int | count() | 连通分量的数量 |
/**
* <b>类 名 称</b> : QuickFind<br/>
* <b>类 描 述</b> : quick find算法实现<br/>
* <b>创 建 人</b> : zhudengkui<br/>
* <b>创建时间</b> : 2021/2/27 22:51<br/>
* <b>修 改 人</b> : zhudengkui<br/>
* <b>修改时间</b> : 2021/2/27 22:51<br/>
* <b>修改备注</b> : <br/>
* quick-find算法分析:<br/>
* find()操作的速度很快,它只需访问id[]数组一次,但其无法处理大型问题,因为对于每一次输入union()都需要
* 扫描整个id[]数组。
* @author zdk
*/
@SuppressWarnings("unused")
public class QuickFind implements UnionFindInterface {
/**
* 分量id,以触点作为索引(索引对应值为当前联通图跟节点的索引)
*/
private int[] id;
/**
* 分量数量(联通图的个数)
*/
private int count;
public QuickFind(int n) {
count = n;
id =new int[n];
for (int i = 0; i < n; i++) {
id[i] = i;
}
}
/**
* 获取联通图的个数
* @return 个数
*/
@Override
public int count() {
return count;
}
/**
* 判断p与q是否联通,即是否在同一联通图上
* @param p p节点
* @param q q节点
* @return 是否联通
*/
@Override
public boolean connected(int p, int q) {
return find(p) == find(q);
}
/**
* 获取p节点所在图的跟节点
* @param p p节点
* @return 根节点索引
*/
@Override
public int find(int p) {
return id[p];
}
/**
* 联通两个节点
* @param p p节点
* @param q q节点
*/
@Override
public void union(int p, int q) {
int pID = find(p);
int qID = find(q);
if (pID == qID) {
return;
}
for (int i = 0; i < id.length; i++) {
if (id[i] == pID) {
id[i] = qID;
}
}
count--;
}
}
/**
* <b>类 名 称</b> : QuickUnion<br/>
* <b>类 描 述</b> : quick-union算法<br/>
* <b>创 建 人</b> : zhudengkui<br/>
* <b>创建时间</b> : 2021/2/27 23:04<br/>
* <b>修 改 人</b> : zhudengkui<br/>
* <b>修改时间</b> : 2021/2/27 23:04<br/>
* <b>修改备注</b> : <br/>
* quick-union算法重点提高了union()方法的速度,它与quick-find算法互补,仅仅是find与union方法实现上的区别
* @author zdk
*/
@SuppressWarnings("unused")
public class QuickUnion implements UnionFindInterface {
/**
* 分量id,以触点作为索引(索引值存储的是其父节点的索引,根节点为自己)
*/
private int[] id;
/**
* 分量数量
*/
private int count;
public QuickUnion(int n) {
count = n;
id = new int[n];
for (int i = 0; i < n; i++) {
id[i] = i;
}
}
@Override
public int count() {
return count;
}
@Override
public boolean connected(int p, int q) {
return find(p) == find(q);
}
@Override
public int find(int p) {
while (p != id[p]) {
p = id[p];
}
return p;
}
@Override
public void union(int p, int q) {
int pID = find(p);
int qID = find(q);
if (pID == qID) {
return;
}
id[pID] = qID;
count--;
}
}
/**
* <b>类 名 称</b> : QuickUnion<br/>
* <b>类 描 述</b> : union-find算法<br/>
* <b>创 建 人</b> : zhudengkui<br/>
* <b>创建时间</b> : 2021/2/27 23:04<br/>
* <b>修 改 人</b> : zhudengkui<br/>
* <b>修改时间</b> : 2021/2/27 23:04<br/>
* <b>修改备注</b> : <br/>
* union-find算法(即加权quick-union算法):union中随意将一棵树连到另一颗树,现在我们会记录每棵树的大小,并总是将较小的树连接到较大的树上<br/>
* 需要添加一个数组和一些代码来记录树中的节点数
* @author zdk
*/
@SuppressWarnings("unused")
public class UnionFind implements UnionFindInterface {
/**
* 分量id,以触点作为索引
*/
private int[] id;
/**
* 记录每棵树(分量)的大小
*/
private int[] sz;
/**
* 分量数量
*/
private int count;
public UnionFind(int n) {
count = n;
id = new int[n];
sz = new int[n];
for (int i = 0; i < n; i++) {
id[i] = i;
sz[i] = 1;
}
}
@Override
public int count() {
return count;
}
@Override
public boolean connected(int p, int q) {
return find(p) == find(q);
}
@Override
public int find(int p) {
while (p != id[p]) {
p = id[p];
}
return p;
}
@Override
public void union(int p, int q) {
int pID = find(p);
int qID = find(q);
if (pID == qID) {
return;
}
if (sz[pID] < sz[qID]) {
id[pID] = qID;
sz[qID] += sz[pID];
} else {
id[qID] = pID;
sz[pID] += sz[qID];
}
count--;
}
}

浙公网安备 33010602011771号