/**
* 数据结构学习之并查集之数组并查集
* @author Sking
*/
package 并查集;
public class ArrayUnionFind {
static int[] equivClass;//元素数组,有效索引从1开始
static int n; //并查集大小
/**
* 根据指定的数组初始容量初始化并查集
* @param numberOfElements 数组初始容量
*/
static void initialize(int numberOfElements) {
n = numberOfElements;
equivClass = new int[n + 1];
//先单独成类,再通过Union算法不断合并
for (int e = 1; e <= n; e++)
equivClass[e] = e;
}
/**
* 将两指定“类”合并
* @param classA “类1”
* @param classB “类2”
*/
public static void union(int classA, int classB) {
for (int k = 1; k <= n; k++)
if (equivClass[k] == classB)
equivClass[k] = classA;
}
/**
* 返回指定元素所属的”类“
* @param theElement 指定元素
* @return 指定元素的”类“
*/
public static int find(int theElement) {
return equivClass[theElement];
}
}
/**
* 数据结构学习之并查集之链表并查集
* @author Sking
*/
package 并查集;
public class LinkedListUnionFind {
/**
* 链表并查集的节点类型
* @author Sking
*/
protected class EquivNode {
/*
* node[e].equivClass既是find(e)返回的值,又是指向等价
* 类node[e].equivClass的链中的第一个结点的指针。
* node[e].size只有当e是链上的第一个结点时才被定义。表
* 示一个类中的结点个数。
*/
int equivClass;//类别标记
int size;//类的节点个数
int next;
/**
* 指定类别和元素个数的构造函数
* @param theClass 类别
* @param theSize 元素个数
*/
EquivNode(int theClass, int theSize) {
equivClass = theClass;
size = theSize;
}
}
private static EquivNode[] node;//节点数组
private static int n;//并查集大小
/**
* 初始化并查集
* @param numberOfElements 并查集容量
*/
public void initialize(int numberOfElements) {
n = numberOfElements;
node = new EquivNode[n + 1];
//初始化,单独成类,类的元素个数均为1
for (int e = 1; e <= n; e++)
node[e] = new EquivNode(e, 1);
}
/**
* 合并两个指定”类“
* @param classA ”类1“
* @param classB ”类2“
*/
public static void union(int classA, int classB) {
//总是将具有较少元素的类链接到较多元素类对应的链中
if (node[classA].size > node[classB].size) {
int t = classA;
classA = classB;
classB = t;
}
int k;
for (k = classA; node[k].next != 0; k = node[k].next)
node[k].equivClass = classB;
node[k].equivClass = classB;
node[classB].size += node[classA].size;
node[k].next = node[classB].next;
node[classB].next = classA;
}
/**
* 查找指定元素所属的类
* @param theElement 指定元素
* @return 指定元素所属的类
*/
public static int find(int theElement) {
return node[theElement].equivClass;
}
}
/*
* 用树结构实现并查集
* 树节点含有两个域parent,root
* parent域用于指示该元素所链接的父节点,根parent域为0.
* root域用于指示这个类中的根,只有根结点的root为true。
* 根结点对应的数组索被记为这个类的类标记。通过从待查询
* 元素结点开始,沿着父链接走到根结点,则根结点的数组索引
* 就是要返回的类标记。
*/
package 并查集;
/*
* 并查集
*/
public class TreeUnionFind {
private static class Node{
int parent;
boolean root;
private Node(){
parent=1;
root=true;
}
}
Node[] node;
public TreeUnionFind(int n){
node=new Node[n+1];
for(int e=0;e<=n;e++)
node[e]=new Node();
}
public int find(int e){
while(!node[e].root)e=node[e].parent;
return e;
}
//A,B表示已经存在的类标记
public void union(int A,int B){
node[A].parent+=node[B].parent;
node[B].root=false;
node[B].parent=A;
}
}
/*
* 改进的并查集,支持压缩路径
*/
package 并查集;
public class TreeUnionFind2 {
private static class Node {
int parent;
boolean root;
private Node() {
parent = 1;
root = true;
}
}
Node[] node;
public TreeUnionFind2(int n) {
node = new Node[n + 1];
for (int e = 0; e <= n; e++)
node[e] = new Node();
}
/*在查找类别的同时进行路径压缩
* 进行路径压缩可以减少查找的时间
*/
public int find(int e) {
int current = e, p, gp;
if (node[current].root)
return current;
p = node[current].parent;
if (node[p].root)
return p;
gp = node[p].parent;
while (true) {
node[current].parent = gp;
if (node[gp].root)
return gp;
current = p;
p = gp;
gp = node[p].parent;
}
}
public void union(int i, int j) {
if (node[i].parent < node[j].parent) {
node[j].parent += node[i].parent;
node[i].root = false;
node[i].parent = j;
} else {
node[i].parent += node[j].parent;
node[j].root = false;
node[j].parent = i;
}
}
}