資料結構 並查集

2021-08-18 16:29:21 字數 2309 閱讀 6987

先看一道題:假如已知有n個人和m對好友關係(存於陣列r),如果兩個人是直接或間接的好友(好友的好友的好友…),則認為他們是屬於同乙個朋友圈,請寫程式求出n個人裡一共有多少個朋友圈。

例如:n=5, m=3, r=,,},表示有5個人,1和2是好友,2和3是好友,4和5是好友,則1,2,3屬於乙個朋友圈,4,5屬於乙個朋友圈,結果為2個朋友圈。

第一種方法:我們可以建立3個set——s1,s2,s3對應3對關係,分別在s2和s3中查詢s1中的0和1,如果找到了,將s2中的元素插入s1中,並清空s2;統計非空set的個數,即可得到朋友圈的個數。

並查集,在一些有n個元素的集合應用問題中,我們通常是在開始時讓每個元素構成乙個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合併,其間要反覆查詢乙個元素在哪個集合中。並查集是一種樹型的資料結構,用於處理一些不想交的集合的合併及查詢問題。在使用中,常常以森林來表示。

每乙個集合以一顆樹來表示,樹的每乙個結點代表集合的乙個元素,開始時,每個元素是乙個自己的集合,因此是乙個森林。類似堆,我們用乙個陣列的下標表示元素名,第i個陣列元素代表它所在的集合的根結點。樹的根結點的下標代表集合名稱,根結點的值表示集合中元素個數。

主要操作有:

初始化:這一步通常只執行一次

查詢:查詢元素所在的集合,即根結點

合併:將兩個元素所在的集合合併​

舉乙個例子:

假設乙個集合s為:s=。

1》初始化:我們全部用-1初始化每乙個樹的根結點

2》合併成以下3個集合:

s1=; s2=; s3=;

其樹形結構如下:

按照上面樹的結構,假設我們的陣列名為a,我們需要執行的操作是,a[0]=a[0]-a[3](因為是負數,所以需要減操作); a[3]=0(3的父結點);

以此類推,我們可以得到這樣的陣列:01

2345

6789

-5-3-20

0001

12我們可以發現,陣列中的負數的絕對值表示的是集合中元素的個數;負數的個數表示集合的個數;非負的數字表示的其下標對應的父結點。

3》假如要將6對應的集合與9對應的集合合併。應該怎麼做?

首先,判斷6和9對應的父結點是不是同乙個結點,如果是同乙個,則說明他們本身就在同乙個集合中;如果不是同乙個,則先找到6和9的父結點——0和2,再執行a[0]=a[0]-a[2]; a[2]=0(2的父結點);

此時陣列變為:01

2345

6789

-7-300

0001

12並查集的**如下

#include 

#include

using

namespace

std;

class unionfind

void union(int x1, int x2)

}size_t count()// 合併後的個數

return count;

}private:

int findroot(int x)// 查詢父結點

private:

vector

_set;

};

此時,再來看我們開頭提的問題,就會變得很簡單了:

size_t friends(const

int n, const

int m, int r[2])

int main()

, , };

cout

<< "朋友圈個數:"

<< friends(n, m, r) << endl;

return

0;}

執行結果:

資料結構 並查集

並查集,顧名思義,合併 查詢 集合 並查集是一種樹型的資料結構,用於處理一些不相交集合 disjoint sets 的合併及查詢問題。常常在使用中以森林來表示。對於概念等等的這裡不再贅述,直接講解應用。應用1 判斷圖中有多少聯通分量 或者圖是否聯通 聯通分量 1 hdu 1213 應用2 判斷圖是否...

資料結構 並查集

time limit 1000ms memory limit 65536k 某城市有n個人,現在給定關於n個人的m條資訊,m條資訊是兩個人在同乙個小區,根據所給資訊,判斷這個城市最多可能有多少個小區。n個人編號為1 n。多組輸入。每組第一行有兩個整數n,m 2 n 50000,0 m n 2 接下來...

資料結構 並查集

一 基本概念 並查集是一種樹型的資料結構,用於處理一些不相交集合 disjoint sets 的合併及查詢問題。常常在使用中以森林來表示。集就是讓每個元素構成乙個單元素的集合,也就是按一定順序將屬於同一組的元素所在的集合合併。在一些有n個元素的集合應用問題中,通常是在開始時讓每個元素構成乙個單元素的...