並查集剖析

2021-06-06 07:21:44 字數 1177 閱讀 3876

1、 概述

並查集(disjoint set或者union-find set)是一種樹型的資料結構,常用於處理一些不相交集合(disjoint sets)的合併及查詢問題。

2、 基本操作

並查集是一種非常簡單的資料結構,它主要涉及兩個基本操作,分別為:

a. 合併兩個不相交集合

b. 判斷兩個元素是否屬於同乙個集合

(1) 合併兩個不相交集合(union(x,y))

合併操作很簡單:先設定乙個陣列father[x],表示x的「父親」的編號。那麼,合併兩個不相交集合的方法就是,找到其中乙個集合最父親的父親(也就是最久遠的祖先),將另外乙個集合的最久遠的祖先的父親指向它。

上圖為兩個不相交集合,b圖為合併後father(b):=father(g)

(2) 判斷兩個元素是否屬於同一集合(find_set(x))

本操作可轉換為尋找兩個元素的最久遠祖先是否相同。可以採用遞迴實現。

3、 優化

(1) find_set(x)時,路徑壓縮

尋找祖先時,我們一般採用遞迴查詢,但是當元素很多亦或是整棵樹變為一條鏈時,每次find_set(x)都是o(n)的複雜度。為了避免這種情況,我們需對路徑進行壓縮,即當我們經過」遞推」找到祖先節點後,」回溯」的時候順便將它的子孫節點都直接指向祖先,這樣以後再次find_set(x)時複雜度就變成o(1)了,如下圖所示。可見,路徑壓縮方便了以後的查詢。

(2) union(x,y)時,按秩合併

即合併的時候將元素少的集合合併到元素多的集合中,這樣合併之後樹的高度會相對較小。

int father[max];   /* father[x]表示x的父節點*/  int rank[max];     /*rank[x]表示x的秩*/      void make_set(int x)      /* 查詢x元素所在的集合,回溯時壓縮路徑*/  int find_set(int x)      return father[x];   }   /*   按秩合併x,y所在的集合   下面的那個if else結構不是絕對的,具體根據情況變化   但是,宗旨是不變的即,按秩合併,實時更新秩。   */  void union(int x, int y)      else     father[x] = y;   }   }

並查集 並查集

本文參考了 挑戰程式設計競賽 和jennica的github題解 陣列版 int parent max n int rank max n void init int n int find int x else void union int x,int y else 結構體版 struct node ...

並查集入門(普通並查集 帶刪除並查集 關係並查集)

什麼是並查集?通俗易懂的並查集詳解 普通並查集 基礎並查集 例題 題解 how many tables problem description lh boy無聊的時候很喜歡數螞蟻,而且,還給每乙隻小螞蟻編號,通過他長期的觀察和記錄,發現編號為i的螞蟻會和編號為j的螞蟻在一起。現在問題來了,他現在只有...

並查集,帶權並查集

題意 ignatius過生日,客人來到,他想知道他需要準備多少張桌子。然而一張桌子上面只能坐上相互熟悉的人,其中熟悉可定義成為a與b認識,b與c認識,我們就說a,b,c相互熟悉 例如a與b熟悉and b與c熟悉,d與e熟悉,此時至少需要兩張桌子。輸入 t表示樣例個數,n表示朋友個數,朋友從1到n編號...