C++并查集常用操作
并查集 是一種樹(shù)型的數(shù)據(jù)結(jié)構(gòu),用于處理一些不相加集合的合并和查詢(xún)問(wèn)題。在使用中常常以森林來(lái)表示。 并查集也是用來(lái)維護(hù)集合的,和前面學(xué)習(xí)的set不同之處在于,并查集能很方便地同時(shí)維護(hù)很多集合。如果用set來(lái)維護(hù)會(huì)非常的麻煩。并查集的核心思想是記錄每個(gè)結(jié)點(diǎn)的父親結(jié)點(diǎn)是哪個(gè)結(jié)點(diǎn)。
前言
并查集是一種多叉樹(shù),用于處理不相交的集合的合并與查詢(xún)問(wèn)題(判斷)。
通俗理解:在日常生活中,我們會(huì)因?yàn)槟硞€(gè)人是自己的朋友,哪怕是朋友的朋友也是有朋友,會(huì)給予通融、 偏袒。而并查集的基本概念,就是判斷某兩個(gè)集合是否是“朋友”關(guān)系,并讓兩個(gè)集合成為“朋友”
常用操作
初始化:每個(gè)結(jié)點(diǎn)單獨(dú)作為一個(gè)集合
查詢(xún):求元素所在的集合的代表元素,即根結(jié)點(diǎn)
合并:將兩個(gè)元素所在的集合,合并為一個(gè)集合
合并之前,應(yīng)先判斷兩個(gè)元素是否屬于同一集合,用上面的“查詢(xún)”來(lái)實(shí)現(xiàn)
算法實(shí)現(xiàn)
初始化:初始的時(shí)候每個(gè)結(jié)點(diǎn)各自為一個(gè)集合,father[i]表示結(jié)點(diǎn) i 的父親結(jié)點(diǎn),如果 father[i]=i,我們認(rèn)為這個(gè)結(jié)點(diǎn)是當(dāng)前集合根結(jié)點(diǎn)(開(kāi)始時(shí)每個(gè)節(jié)點(diǎn)根節(jié)點(diǎn)是他自己)。
void init() {
for (int i = 1; i <= n; ++i) {
father[i] = i;
}
}
查找:查找結(jié)點(diǎn)所在集合的根結(jié)點(diǎn),結(jié)點(diǎn) x 的根結(jié)點(diǎn)必然也是其父親結(jié)點(diǎn)的根結(jié)點(diǎn)(像是有遞歸的樣子)。
int get(int x) {
if (father[x] == x) { // x 結(jié)點(diǎn)就是根結(jié)點(diǎn)
return x;
}
return get(father[x]); // 如果該節(jié)點(diǎn)不是根節(jié)點(diǎn),繼續(xù)尋找父結(jié)點(diǎn)的根結(jié)點(diǎn)
}
合并:將兩個(gè)元素所在的集合合并在一起,通常來(lái)說(shuō),合并之前先判斷兩個(gè)元素是否屬于同一集合。
void hebing(int x, int y) {
x = find(x);
y = find(y);
if (x != y) { // 不在同一個(gè)集合
father[y] = x;//將根節(jié)點(diǎn)合并
}
}
上面三個(gè)操作是并查集常用的操作
前面的并查集的復(fù)雜度實(shí)際上在有些極端情況會(huì)很慢。比如樹(shù)的結(jié)構(gòu)正好是一條鏈,那么最壞情況下,每次查詢(xún)的復(fù)雜度達(dá)到了O(n) 。這并不是我們期望的結(jié)果。路徑壓縮的思想是,我們只關(guān)心每個(gè)結(jié)點(diǎn)的父結(jié)點(diǎn),而并不太關(guān)心樹(shù)的真正的結(jié)構(gòu)(遞歸查找相當(dāng)浪費(fèi)時(shí)間)如下:

當(dāng)想去訪問(wèn)6的根節(jié)點(diǎn)時(shí),要訪問(wèn)5的根節(jié)點(diǎn),想去訪問(wèn)5的根節(jié)點(diǎn),又要去訪問(wèn)4的根節(jié)點(diǎn)..........以此類(lèi)推,此時(shí)并查集退化為線性。
這樣我們?cè)谝淮尾樵?xún)的時(shí)候,可以把查詢(xún)路徑上的所有結(jié)點(diǎn)的father[i]都賦值成為根結(jié)點(diǎn)。只需要在我們之前的查詢(xún)函數(shù)上面進(jìn)行很小的改動(dòng)
int findf(int k)
{ if(f[k] == k)
return k;
return f[k] = findf(f[k]); //后來(lái)更新的點(diǎn)的根節(jié)點(diǎn)直接為最開(kāi)始的點(diǎn),一步找到總根節(jié)點(diǎn)。
}
初步學(xué)習(xí)理解,如有不足請(qǐng)指出,謝謝
到此這篇關(guān)于C++并查集基礎(chǔ)的文章就介紹到這了,更多相關(guān)C++并查集內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++?LeetCode1769移動(dòng)所有球到每個(gè)盒子最小操作數(shù)示例
這篇文章主要為大家介紹了C++?LeetCode1769移動(dòng)所有球到每個(gè)盒子所需最小操作數(shù)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
C語(yǔ)言實(shí)現(xiàn)memcpy函數(shù)的使用示例
在C語(yǔ)言中,我們可以自己實(shí)現(xiàn) memcpy 函數(shù)來(lái)實(shí)現(xiàn)內(nèi)存數(shù)據(jù)的拷貝操作,本文就來(lái)介紹一下C語(yǔ)言實(shí)現(xiàn)memcpy函數(shù)的使用示例,感興趣的可以了解一下2023-09-09
使用C++ MFC編寫(xiě)一個(gè)簡(jiǎn)單的五子棋游戲程序
這篇文章主要介紹了使用C++ MFC編寫(xiě)一個(gè)簡(jiǎn)單的五子棋游戲程序,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
Opencv基于CamShift算法實(shí)現(xiàn)目標(biāo)跟蹤
這篇文章主要為大家詳細(xì)介紹了Opencv基于CamShift算法實(shí)現(xiàn)目標(biāo)跟蹤,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
C語(yǔ)言簡(jiǎn)單實(shí)現(xiàn)門(mén)禁系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言簡(jiǎn)單實(shí)現(xiàn)門(mén)禁系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
C++實(shí)現(xiàn)的大數(shù)相乘算法示例
這篇文章主要介紹了C++實(shí)現(xiàn)的大數(shù)相乘算法,結(jié)合實(shí)例形式分析了C++大數(shù)相乘的概念、原理及代碼實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-08-08
簡(jiǎn)單總結(jié)C++中指針常量與常量指針的區(qū)別
這里我們來(lái)簡(jiǎn)單總結(jié)C++中指針常量與常量指針的區(qū)別,包括如何聲明和使用常量指針以及指針常量,需要的朋友可以參考下2016-06-06
OpenCV cv.Mat與.txt文件數(shù)據(jù)的讀寫(xiě)操作
這篇文章主要介紹了OpenCV cv.Mat 與 .txt 文件數(shù)據(jù)的讀寫(xiě)操作,現(xiàn)在分享給大家,也給大家做個(gè)參考2018-05-05

