并查集顾名思义有两个功能,,
一是查询两个节点在不在一个集合,这可以通过递归对父节点的应用实现查询根节点,只要两节点根节点相同则在一个集合
二是把两个集合并在一起,这可以通过把一个集合的根节点的父节点指针指向另一个集合的根节点。
目录
1.测试程序
public static void main(String[] args) {
int[] data = {-1, 0, -1, 0, 2, -1, 0, 4, 5, 8};
//测试基本操作
for (int i = 0; i < 10; i++) {
data[i] = findRoot(data, i);
tellRoot(data, i);
}
System.out.println(Arrays.toString(data));
System.out.println("0,2在一个集合:"+areAGroup(data, 0, 2));
Union(data, 0, 2);
//测试两集合结合后的效果
System.out.println(Arrays.toString(data));
System.out.println("0,2在一个集合:"+areAGroup(data, 0, 2));
}
2.寻根,并压缩路径的方法
//寻找根节点,并同时压缩路径的方法:输入数组和节点位置,将节点内容从父节点改为根节点
public static int findRoot(int[] deposit, int node) {
if (deposit[node] >= 0) {
return findRootDetail(deposit, deposit[node]);
} else {
return deposit[node];//本身是根节点,直接返回节点存储值即可
}
}
public static int findRootDetail(int[] deposit, int node) {
if(deposit[node] < 0) {//如果该节点内容小于0则该节点为根节点
return node;
} else {
return findRootDetail(deposit, deposit[node]);//路径压缩
}
}
3.告诉根节点集合有多少节点的方法
//告诉根节点,有新节点以此点为根节点的方法
public static void tellRoot(int[] deposit, int node) {
if(deposit[node] >= 0) { //如果本身是根节点不用减减,因为本来就有-1
tellRootDetail(deposit, deposit[node]);
}
}
public static void tellRootDetail(int[] deposit, int node) {
if(deposit[node] < 0) {
deposit[node]--;//告诉根节点,有新节点以此点为根节点
} else {
tellRootDetail(deposit, deposit[node]);
}
}
4.集合的并运算
//集合的并运算
public static void Union(int[] deposit, int root1, int root2) {
//小集合并入大集合树高增长慢
if (deposit[root1] > deposit[root2]) {
deposit[root2] += deposit[root1];//root2节点数增加
deposit[root1] = root2;//小树根节点父节点改为大树根节点
} else {
deposit[root1] += deposit[root2];//root2节点数增加
deposit[root2] = root1;
}
}
5.确认两节点是否在一集合
//确认两节点是否在一集合
public static boolean areAGroup(int[] deposit, int node1, int node2) {
int node1Root = findRoot(deposit, node1);
int node2Root = findRoot(deposit, node2);
//由于根节点是-1,有三种情况两节点在一集合,1.两节点指向的根节点的量都为正数且相同,2.节点1的根节点指针指向节点2,节点2根节点指针为负数 3.第2种情况反过来
if (node1Root == node2Root || node1Root == node2 || node2Root == node1) {
return true;
} else {
return false;
}
}
全部代码
import java.util.*;
public class test {
public static void main(String[] args) {
int[] data = {-1, 0, -1, 0, 2, -1, 0, 4, 5, 8};
for (int i = 0; i < 10; i++) {
data[i] = findRoot(data, i);
tellRoot(data, i);
}
System.out.println(Arrays.toString(data));
System.out.println("0,2在一个集合:"+areAGroup(data, 0, 2));
Union(data, 0, 2);
System.out.println(Arrays.toString(data));
System.out.println("0,2在一个集合:"+areAGroup(data, 0, 2));
}
//寻找根节点,并同时压缩路径的方法:输入数组和节点位置,将节点内容从父节点改为根节点
public static int findRoot(int[] deposit, int node) {
if (deposit[node] >= 0) {
return findRootDetail(deposit, deposit[node]);
} else {
return deposit[node];//本身是根节点,直接返回节点存储值即可
}
}
public static int findRootDetail(int[] deposit, int node) {
if(deposit[node] < 0) {//如果该节点内容小于0则该节点为根节点
return node;
} else {
return findRootDetail(deposit, deposit[node]);//路径压缩
}
}
//告诉根节点,有新节点以此点为根节点的方法
public static void tellRoot(int[] deposit, int node) {
if(deposit[node] >= 0) { //如果本身是根节点不用减减,因为本来就有-1
tellRootDetail(deposit, deposit[node]);
}
}
public static void tellRootDetail(int[] deposit, int node) {
if(deposit[node] < 0) {
deposit[node]--;//告诉根节点,有新节点以此点为根节点
} else {
tellRootDetail(deposit, deposit[node]);
}
}
//集合并运算
public static void Union(int[] deposit, int root1, int root2) {
//小集合并入大集合树高增长慢
if (deposit[root1] > deposit[root2]) {
deposit[root2] += deposit[root1];//root2节点数增加
deposit[root1] = root2;//小树根节点父节点改为大树根节点
} else {
deposit[root1] += deposit[root2];//root2节点数增加
deposit[root2] = root1;
}
}
//确认两节点是否在一集合
public static boolean areAGroup(int[] deposit, int node1, int node2) {
int node1Root = findRoot(deposit, node1);
int node2Root = findRoot(deposit, node2);
//由于根节点是-1,有三种情况两节点在一集合,1.两节点指向的根节点的量都为正数且相同,2.节点1的根节点指针指向节点2,节点2根节点指针为负数 3.第2种情况反过来
if (node1Root == node2Root || node1Root == node2 || node2Root == node1) {
return true;
} else {
return false;
}
}
}