Java數(shù)據(jù)結(jié)構(gòu)之并查集的實現(xiàn)
并查集就是將原本不在一個集合里面的內(nèi)容合并到一個集合中。
在實際的場景中用處不多。
除了出現(xiàn)在你需要同時去幾個集合里面查詢,避免出現(xiàn)查詢很多次,從而放在一起查詢的情況。
下面簡單實現(xiàn)一個例子,我們來舉例說明一下什么是并查集,以及究竟并查集解決了什么問題。
代碼解析
package com.chaojilaji.book.andcheck;
public class AndCheckSet {
public static Integer getFather(int[] father, int u) {
if (father[u] != u) {
father[u] = getFather(father, father[u]);
}
return father[u];
}
public static void join(int[] father,int x, int y) {
int fx = getFather(father,x);
int fy = getFather(father,y);
if (fx != fy){
father[fx] = fy;
}
}
public static void main(String[] args) {
int n = 10;
int[] a = new int[n];
for (int i = 0;i<n;i++){
a[i] = i; // 初始化定義一百個集合
}
for (int i=0;i<n;i++){
System.out.println(i+" "+getFather(a, i)); // 對于每個集合,父節(jié)點都是自己
}
}
}首先,我們定義了兩個函數(shù),分別為getFather和join,分別表示獲取u所在集合的根以及合并兩個集合。
先來看看getFather方法
public static Integer getFather(int[] father, int u) {
if (father[u] != u) {
father[u] = getFather(father, father[u]);
}
return father[u];
}是找出值u所在集合的根節(jié)點是多少。一般來說,father[u]如果等于u本身,那么說明u所在節(jié)點就是根節(jié)點,而這個算法是直到相等才退出,也就是說,對于從u到根節(jié)點的每個節(jié)點的father都被直接置為根節(jié)點,同時返回了當前節(jié)點的根節(jié)點。
然后來看看join方法
public static void join(int[] father,int x, int y) {
int fx = getFather(father,x);
int fy = getFather(father,y);
if (fx != fy){
father[fx] = fy;
}
}分別找出x和y兩個節(jié)點所在集合的根節(jié)點,如果根節(jié)點不一樣,則將其中一個節(jié)點的father節(jié)點置為另一個節(jié)點即可,這樣就合并成了一個集合。
代碼應用
public static void main(String[] args) {
int n = 10;
int[] a = new int[n];
for (int i = 0;i<n;i++){
a[i] = i; // 初始化定義n個集合
}
for (int i=0;i<n;i++){
System.out.println(i+" "+getFather(a, i)); // 對于每個集合,父節(jié)點都是自己
}
System.out.println("-------------------------");
join(a,0,1); // 合并 0 和 1
for (int i=0;i<n;i++){
System.out.println(i+" "+getFather(a, i));
}
// 由于合并了0和1,所以集合變成了9個,節(jié)點0和節(jié)點1的根都是節(jié)點1
System.out.println("-------------------------");
join(a,2,3); // 合并 2 和 3
for (int i=0;i<n;i++){
System.out.println(i+" "+getFather(a, i));
}
// 由于合并了2和3,所以集合變成8個,節(jié)點2和節(jié)點3的根都是節(jié)點3
System.out.println("-------------------------");
join(a,1,3); // 合并 1 和 3
for (int i=0;i<n;i++){
System.out.println(i+" "+getFather(a, i));
}
// 由于合并了1和3,所以集合變成7個,節(jié)點0,1,2,3的根都是節(jié)點3
}首先,我們定義了n個集合,這n個集合的值是0~n-1,然后此時他們的父節(jié)點均等于他們本身,所以這就是n個獨立的集合,結(jié)果如下
0的父節(jié)點為 0 1的父節(jié)點為 1 2的父節(jié)點為 2 3的父節(jié)點為 3 4的父節(jié)點為 4 5的父節(jié)點為 5 6的父節(jié)點為 6 7的父節(jié)點為 7 8的父節(jié)點為 8 9的父節(jié)點為 9
然后調(diào)用 join(a,0,1)合并0集合和1集合,再輸出節(jié)點父集合情況為
0的父節(jié)點為 1 1的父節(jié)點為 1 2的父節(jié)點為 2 3的父節(jié)點為 3 4的父節(jié)點為 4 5的父節(jié)點為 5 6的父節(jié)點為 6 7的父節(jié)點為 7 8的父節(jié)點為 8 9的父節(jié)點為 9
可以看見,由于合并了0和1,所以集合變成了9個,節(jié)點0和節(jié)點1的根都是節(jié)點1。
然后調(diào)用 join(a,2,3) 合并2集合和3集合,輸出節(jié)點父集合情況為
0的父節(jié)點為 1 1的父節(jié)點為 1 2的父節(jié)點為 3 3的父節(jié)點為 3 4的父節(jié)點為 4 5的父節(jié)點為 5 6的父節(jié)點為 6 7的父節(jié)點為 7 8的父節(jié)點為 8 9的父節(jié)點為 9
可以看見,由于合并了2和3,所以集合變成8個,節(jié)點2和節(jié)點3的根都是節(jié)點3。
最后,我們再調(diào)用join(a,1,3) 合并1集合和3集合,輸出節(jié)點父集合情況為
0的父節(jié)點為 3 1的父節(jié)點為 3 2的父節(jié)點為 3 3的父節(jié)點為 3 4的父節(jié)點為 4 5的父節(jié)點為 5 6的父節(jié)點為 6 7的父節(jié)點為 7 8的父節(jié)點為 8 9的父節(jié)點為 9
可以看出來,由于合并了1和3,所以集合變成7個,節(jié)點0,1,2,3的根都是節(jié)點3。
實際應用
代碼的層面來講,并查集很好實現(xiàn)。但是我們卻也可以發(fā)現(xiàn),其應用場景似乎非常局限。
首先,我們需要定義出一個father[x] = x的數(shù)組,然后我們再去合并。似乎很難想到應用場景。
那么我們可以想象一個場景,現(xiàn)在有個網(wǎng)絡拓撲圖,里面有n和網(wǎng)絡設(shè)施設(shè)備,然后又給了你這n個設(shè)施設(shè)備之間的連接關(guān)系,問你一共有多少個局部聯(lián)通網(wǎng)。
對于這個問題,我們就可以首先定義每個設(shè)備自己跟自己相連,然后每出現(xiàn)一條邊,就對這兩個設(shè)備采取join操作。最終我們在遍歷完所有的節(jié)點,得到多少個不同的father,即表示有多少個不同的局部聯(lián)通網(wǎng)。
這樣的問題還可以延伸到我們的人際交友圈,首先每個人都是單獨的集合,在不斷認識人的過程中,產(chǎn)生連通性。最終讓你確認一共有多少個不互通的人際圈。
所以你會發(fā)現(xiàn),這本質(zhì)上就是求圖論中連通塊的個數(shù)。
到此這篇關(guān)于Java數(shù)據(jù)結(jié)構(gòu)之并查集的實現(xiàn)的文章就介紹到這了,更多相關(guān)Java并查集內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在MyBatis中使用 # 和 $ 書寫占位符的區(qū)別說明
這篇文章主要介紹了在MyBatis中使用 # 和 $ 書寫占位符的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10
初識Java基礎(chǔ)之數(shù)據(jù)類型與運算符
Java是一種強類型語言,每個變量都必須聲明其數(shù)據(jù)類型,下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)之數(shù)據(jù)類型與運算符的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2021-10-10
Spring Cloud入門教程之Zuul實現(xiàn)API網(wǎng)關(guān)與請求過濾
這篇文章主要給大家介紹了關(guān)于Spring Cloud入門教程之Zuul實現(xiàn)API網(wǎng)關(guān)與請求過濾的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-05-05
Jmeter對響應數(shù)據(jù)實現(xiàn)斷言代碼實例
這篇文章主要介紹了Jmeter對響應數(shù)據(jù)實現(xiàn)斷言代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09

