並查集顧名思義有兩個功能,,
一是查詢兩個節點在不在一個集合,這可以通過遞歸對父節點的應用實現查詢根節點,只要兩節點根節點相同則在一個集合
二是把兩個集合併在一起,這可以通過把一個集合的根節點的父節點指針指向另一個集合的根節點。
目錄
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;
}
}
}