并查集基礎

abstract

并查集(Union-Find Set)是一種數據結構,主要用于處理動態連通性問題(Dynamic Connectivity Problem),例如在圖論中判斷兩點是否屬于同一個連通分量,以及動態地合并集合。

它廣泛應用于解決最小生成樹(Minimum Spanning Tree)、網絡連接問題等領域。

并查集的概念

并查集是一種簡單的集合表示,它支持以下3種操作:

  1. Initial(S):將集合S中的每個元素都初始化為只有一個單元素的子集合
  2. Union(S, Root1, Root2):把集合S中的子集合Root2并入子集合Root1。要求Root1和Root2不相交,否則不執行合并。
  3. Find(S, x):找到集合S中單元x所在的子集合,并返回該子集合的根結點

集合和動態連通性

并查集維護的是一些不相交的集合(Disjoint Sets)

例如,有元素集合 {1, 2, 3, 4, 5},可以有如下集合劃分:

  • 初始狀態:{ {1}, {2}, {3}, {4}, {5} }
  • 合并 {1}{2}{ {1, 2}, {3}, {4}, {5} }
  • 再合并 {3}{4}{ {1, 2}, {3, 4}, {5} }
  • 判斷 12 是否屬于同一集合:否

并查集的存儲結構

通常用樹的雙親表示法作為并查集的存儲結構,每個子集合是一棵樹表示。

所有表示子集合的樹,構成一個森林。存放在雙親表示數組

通常使用數組元素的下標代表集合中的元素(名字),用根節點的下標代表子集合名字

樹中每個結點的雙親指針指向父節點,根結點的雙親指針為負數(可設置為該集合元素數量的相反數)。

在采用樹的雙親指針數組表示作為并查集的存儲表示時,集合元素的編號從0到SIZE-1
其中SIZE是最大元素的個數。


初始化示例

集合 S = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } S=\set{0,1,2,3,4,5,6,7,8,9} S={0,1,2,3,4,5,6,7,8,9},初始時每個元素自成一個單元素子集合。

數組表示:

下標0123456789
父節點-1-1-1-1-1-1-1-1-1-1

子集合的合并示例

例如,經過一定計算,子集合并為3個更大的子集合

  • S 1 = { 0 , 6 , 7 , 8 } S_1 = \set{0, 6, 7, 8} S1?={0,6,7,8}
  • S 2 = { 1 , 4 , 9 } S_2 = \set{1, 4, 9} S2?={1,4,9}
  • S 3 = { 2 , 3 , 5 } S_3 = \set{2, 3, 5} S3?={2,3,5}
樹狀表示:
S1
0
6
7
8
S2
1
4
9
S1
2
3
5

三個子集的名字分別用根節點 0 , 1 , 2 0,1,2 0,1,2表示

例如,在存儲結構(雙親表示)中,元素(結點) 6 , 7 , 8 6,7,8 6,7,8的雙親結點為結點 0 0 0;于是在雙親表示數組中,下標為 6 , 7 , 8 6,7,8 6,7,8的數組分量中的值都指示 0 0 0,表明結點 6 , 7 , 8 6,7,8 6,7,8處在結點 0 0 0所表示的子集中(子集名為0),而結點0本身對應的數組分量存放的是子集0中包含的元素數量的相反數(是個負數)

其余兩個子集類似

數組表示:
下標0123456789
父節點-4-3-32120001

說明:

  • 負數表示根結點,數值是集合中元素的數量(取反)。
  • 例如下標 0 的值 -4 表示集合 S 1 S_1 S1? 包含4個元素。

集合的合并操作

為將兩個子集合合并,需將其中一個集合的根結點的雙親指針指向另一個集合的根結點。

例如合并 S 12 = S 1 ∪ S 2 S_{12}=S_1\cup S_2 S12?=S1?S2? ,結果如下:

樹狀表示:
S2
S1
0
1
4
6
7
8
9
下標0123456789
父節點-70-32120001

說明:

可以看到,在這類合并操作執行后,雙親表示數組中,如果要找到元素4所在集合 S 12 S_{12} S12?的根節點,就不能保證S[4]是所需要的答案(本例中S[4]=1不是 S 12 S_{12} S12?的根節點;需要繼續向上跟蹤,再次訪問S[S[4]]=S[1]=0,0還不是負數,所以要再次跟蹤,S[0],發現S[0]=-7,由此可知0就是最初元素4所在子集合的根節點

這種改變讓查詢變得不夠直接,可以通過路徑壓縮操作來改進

并查集的基本實現

并查集的結構定義如下:

#define SIZE 100
int UFSets[SIZE]; //集合元素數組 (雙親指針數組)

下面是并查集主要運算的實現。
(1)并查集的初始化操作(雙親表示數組中對應分量設置為-1,表示初始每個子集僅有一個元素)

void Initial(int S[]) {for(int i=0; i<SIZE; i++)//每個元素自成單元素集合S[i] = -1;
}

(2)并查集的Find操作
在并查集S中查找并返回包含元素x的樹的根。

int Find(int S[], int x) {while(S[x] >= 0)//循環尋找x,直到S[x]是負數為止(離開循環時,x是非負的,S[x]是負數)x = S[x];//更新x(這里保證x是非負的)return x;//返回非負的值,表示元素x所在子集的根節點
}

判斷兩個元素是否屬于同一集合,只需分別找到它們的根,再比較根是否相同即可。
(3)并查集的Union操作
求兩個不相交子集合的并集。

若將兩個元素所在的集合合并為一個集合,則需要先找到兩個元素的根,再令一棵子集樹的根指向另一棵子集樹的根

void Union(int S[], int Root1, int Root2) {if(Root1 == Root2) return;//兩個根相同不合并S[Root2] = Root1;//根不同,將用其中一個根Root2的雙親結點指向另一個根Root1
}

小結

Find操作和Union操作的時間復雜度分別為O(d)和O(1),其中d為樹的深度。

并查集實現的優化

在極端情況下, n n n個元素構成的集合樹的深度為n,則Find操作的最壞時間復雜度為O(n)。

改進的辦法是:在做Union操作之前,首先判別子集中的成員數量,然后令成員少的根指向成員多的根,即把小樹合并到大樹,為此可令根結點的絕對值保存集合樹中的成員數量
(1)改進的Union操作

void Union(int S[], int Root1, int Root2) {if(Root1 == Root2) return;//(負數的絕對值越小,值越大abs(S[Root2])<abs(S[Root1],則S[Root2] > S[Root1])if(S[Root2] > S[Root1]) { // Root2 結點數更少)S[Root1] += S[Root2]; // 累加集合樹的結點總數S[Root2] = Root1;      // 小樹合并到大樹} else {S[Root2] += S[Root1]; // 累加結點總數S[Root1] = Root2;     // 小樹合并到大樹}
}

采用這種方法構造得到的集合樹,其深度不超過 log ? 2 n + 1 \log_2 n + 1 log2?n+1(這里 n n n為元素數量)

隨著子集逐對合并,集合樹的深度越來越大,為了進一步減少確定元素所在集合的時間,還可進一步對上述Find操作進行優化,當所查元素 x x x不在樹的第二層時,在算法中增加一個“壓縮路徑”的功能,即將從根到元素x路徑上的所有元素都變成根的孩子

例如 r o o t , p 1 , p 2 , . . . , p m , x , . . . {root,p_1,p_2,...,p_m,x,...} root,p1?,p2?,...,pm?,x,...,通過壓縮操作,比如依次將 x , p m , ? , p 2 , p 1 {x,p_{m},\cdots,p_{2},p_{1}} x,pm?,?,p2?,p1?掛到 r o o t root root結點下;

而掛到root結點下這個操作對于雙親表示法,就是將對應的結點的數組分量(父節點)設置為root;

(2)改進find操作

int Find(int S[], int x) {int root=x;//根節點編號初始化為x//找到x所在子集根節點while(s[root]>=0)root=s[root];//這時候已經找到root了,但是為了之后的新查找更快,做路徑壓縮while(x!=root){//壓縮路徑(將樹的高于第2層的結點進行壓縮)int t=S[x];//t指向x的父節點(以便于處理完x沿著路徑往祖先結點繼續處理)S[x]=root;//x直接掛到根節點下面x=t;//更新下一個需要處理的目標}return root;//返回根節點編號
}

通過 Find 操作的“壓縮路徑”優化后,可使集合樹的深度不超過 O ( α ( n ) ) O(\alpha(n)) O(α(n)),其中 α ( n ) \alpha(n) α(n) 是一個增長極其緩慢的函數,對于常見的正整數 n n n,通常 α ( n ) ≤ 4 \alpha(n) \leq 4 α(n)4

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/62953.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/62953.shtml
英文地址,請注明出處:http://en.pswp.cn/web/62953.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CloudberryDB(一)安裝部署多節點分布式數據庫集群

CloudberryDB&#xff1a; 一個 Greenplum Database 分布式數據庫開源版本的衍生項目&#xff0c; 針對開源 Greenplum Database 優化的地方&#xff0c; CloudberryDB制定了路線圖&#xff08;https://github.com/orgs/cloudberrydb/discussions/369&#xff09;并在逐步改…

解決Logitech G hub 無法進入一直轉圈的方案(2024.12)

如果你不是最新版本無法加載嘗試以下方案&#xff1a;刪除AppData 文件夾下的logihub文件夾 具體路徑&#xff1a;用戶名根據實際你的請情況修改 C:\Users\Administrator\AppData\Local 如果你有通過lua編譯腳本&#xff0c;記得備份&#xff01;&#xff01; ↓如果你是最新…

數據庫范式與反范式化:如何權衡性能與數據一致性

目錄 1. 什么是數據庫范式&#xff08;Normalization&#xff09;&#xff1f;第一范式&#xff08;1NF&#xff09;第二范式&#xff08;2NF&#xff09;第三范式&#xff08;3NF&#xff09; 2. 什么是反范式化&#xff08;Denormalization&#xff09;&#xff1f;3. 反范式…

Nmap使用總結

0X00 背景 nmap是測試中常用的網絡探測工具&#xff0c;但是這回簡單的操作&#xff0c;一直了解不深入&#xff0c;現在深入的了解和學習一下。 在文章結構上&#xff0c;我把平時常用的內容提前了&#xff0c;以便再次查閱的時候&#xff0c;比較方便。 0X01 安裝 nmap可…

【記錄49】vue2 vue-office在線預覽 docx、pdf、excel文檔

vue2 在線預覽 docx、pdf、excel文檔 docx npm install vue-office/docx vue-demi0.14.6 指定版本 npm install vue-office/docx vue-demi <template><VueOfficeDocx :src"pdf" style"height: 100vh;" rendere"rendereHandler" error&…

MVC模式的理解和實踐

在軟件開發中&#xff0c;MVC&#xff08;Model-View-Controller&#xff09;模式是一種經典的設計模式&#xff0c;特別適用于構建用戶界面復雜的Web應用程序。MVC通過將應用程序的業務邏輯、數據顯示和用戶交互分離&#xff0c;使代碼結構更加清晰&#xff0c;易于維護和擴展…

[A-22]ARMv8/v9-SMMU多級頁表架構

ver0.1 [看前序文章有驚喜,關注W\X\G=Z+H=“浩瀚架構師”,可以解鎖全部文章] 前言 前文我們對SMMU的系統架構和基本功能做了簡要的介紹,現在大家大致對SMMU在基于ARM體系的系統架構下的總線位置和產品形態有了基本的了解。這里我們還是簡單做個前情回顧,從總線架構角度看…

【UE5 “RuntimeLoadFbx”插件】運行時加載FBX模型

前言 為了解決在Runtime時能夠直接根據FBX模型路徑直接加載FBX的問題&#xff0c;推薦一款名為“RuntimeLoadFBX”的插件。 用法 插件用法如下&#xff0c;只需要指定fbx的地址就可以在場景中生成Actor模型 通過指定輸入參數“Cal Collision”來設置FBX模型的碰撞 還可以通過…

(11)(3.1) ESC接地和接線注意事項

文章目錄 前言 1 歸納 2 電容式 3 電阻 前言 ESC 接地問題由 3 種形式的 ESC 信號/耦合問題組成&#xff0c;即電阻、電容和電感。在制造飛機時&#xff0c;應考慮這三個因素。 1 歸納 這是電流突然變化導致系統中出現大電壓尖峰的趨勢。電源系統中的電感主要是由 ESC 和…

精品基于Python實現的微信小程序校園導航系統-微信小程序

[含文檔PPT源碼等] [包運行成功永久免費答疑輔導] 《django微信小程序校園導航系統》該項目采用技術Python的django框架、mysql數據庫 &#xff0c;項目含有源碼、文檔、PPT、配套開發軟件、軟件安裝教程、項目發布教程、核心代碼介紹視頻等 軟件開發環境及開發工具&#xf…

Rstudio-server的安裝、配置、維護

一、安裝Rstudio-server (1)安裝R語言&#xff1a; sudo apt install r-base # 如果沒有管理員權限無法操作 # 這樣裝上R默認在/usr/bin/R其實基本上的流程都可以參考posit的官網&#xff08;也就是Rstudio的官網&#xff09;&#xff1a; https://posit.co/download/rstudio…

Python序列的應用(八):元組、字典

前言&#xff1a;在Python編程語言中&#xff0c;序列是一種非常重要的數據結構&#xff0c;它允許我們存儲和操作有序的數據集合。在前幾期的內容中&#xff0c;我們已經探討了列表&#xff08;List&#xff09;和集合&#xff08;Set&#xff09;這兩種序列的應用&#xff0c…

OpenCV 功能函數介紹

一&#xff0c; 二值化函數 功能&#xff1a; 用于對圖像進行二值化處理 參數&#xff1a; cv2.threshold(輸入你的圖像所對應的灰度圖&#xff0c; 閾值&#xff1a;是浮點還是整數取決予圖像的數據類型 最大值;高于閾值的像素值&#xff0c; 閾值類型&#xff1a;cv2.THR…

【Python】使用Selenium的find_element模塊獲取網頁上的大段文字和表格的方法(建議收藏!)

發現了一個使用Selenium的find_element模塊&#xff0c;快速獲取文字和表格的方法&#xff0c;很實在&#xff0c;以后爬網的時候&#xff0c;就不用beautifulSoup 和 pandas的read_html 混起來用了&#xff01; 文字部分&#xff1a;實現網絡節點下&#xff0c;某個節點下的其…

APP滲透測試記錄(一、Android應用基本構造)

Android應用基本構造 雷電模擬機進入 adb shell# 如果不是root權限 su一下 su 1.了解APK文件 安卓應用的擴展名為.apk(Android Application Package),它是一個包含多個文件和文件夾的數據存檔文件。 1.1 apk文件解壓后的目錄結構 AndroidManifest.xml:包含應用的大部分…

【AI知識】有監督學習之回歸任務(附線性回歸代碼及可視化)

1. 回歸的基本概念 在機器學習的有監督學習中&#xff0c;回歸&#xff08;Regression&#xff09;是一種常見的任務&#xff0c;它的目標是通過觀察數據來建立一個模型&#xff0c;用一個或多個自變量來預測因變量的值。 回歸分析通常用于&#xff1a; a.預測&#xff0c;基于…

fastadmin批量壓縮下載遠程視頻文件

后端代碼 // 批量下載并壓縮 public function downloadAll(){$ids input(ids);$row $this->model->where(id, in, $ids)->field(id,title,video_url)->select();if (!$row) {$this->error(記錄不存在);}$arr [];$tempFiles []; // 用來存儲臨時下載的視頻文…

邊緣計算+人工智能:讓設備更聰明的秘密

引言&#xff1a;日常生活中的“智能”設備 你是否發現&#xff0c;身邊的設備正變得越來越“聰明”&#xff1f; 早上醒來時&#xff0c;智能音箱已經根據你的日程播放舒緩音樂&#xff1b;走進廚房&#xff0c;智能冰箱提醒你今天的食材庫存&#xff1b;而在城市道路上&…

JVM 雙親委派模型以及垃圾回收機制

目錄 1. JVM 內存區域劃分 2. JVM 中類加載的過程 1) 類加載的基本流程 2) 雙親委派模型 3. JVM 中垃圾回收機制 1) 找到垃圾 a) 引用計數 b) 可達性分析 2) 釋放垃圾 1. JVM 內存區域劃分 一個運行起來的 Java 進程&#xff0c;其實就是一個 JVM 虛擬機。 而進程是…

ansible自動化運維(四)jinjia2模板

Jinjia2模板 前面說到playbook組成的時候&#xff0c;有介紹到template模塊&#xff0c;而template模塊對模板文件進行渲染時&#xff0c;使用的就是jinja2模板引擎&#xff0c;jinja2本身就是基于python的模板引擎&#xff0c;所以下面先來了解一下jinjia2模板的一些用法 基…