1. 程式人生 > 其它 >vue2 元件通訊

vue2 元件通訊

技術標籤:演算法模板演算法資料結構java

目錄

定義

並查集是一種樹形的資料結構,主要支援這兩個操作:1)詢問兩個元素是否屬於同一個子集,即find操作;2)將兩個元素所屬的子集合並,即union操作
並查集可以在近乎 O ( 1 ) O(1) O(1)的時間複雜度裡完成上述兩個操作。

實現思路

在並查集中,每個子集用一棵樹來表示,樹的根節點編號就是子集的編號。通常使用一維陣列 p p p來進行儲存, p [ x ] p[x] p[x]表示節點 x x x的父節點。

1)如何判斷是否為根節點?
根節點的父節點為自身,因此,判斷p[x] == x的真假即可判斷是否為根節點,若該式為True,則為根節點。

2)find(x)操作——如何求得節點 x x x所屬的子集編號?
使用下述程式碼可求得子集編號:

while(p[x] != x) x = p[x];

但為了避免並查集所表示的樹形結構高度過高,影響查詢效能,通常會針對樹的高度進行路徑壓縮。路徑壓縮的效果是:在查詢一個節點 a a a所屬子集編號的同時,把節點 a a a到根節點的沿途所有節點的父節點都指向根節點,如下圖所示。並查集的特點就是,一邊查詢一邊修改節點的指向。(本段文字以及圖片,引自這裡

3)union(x, y)操作——如何兩個節點所屬的子集?
對於節點 x x x和節點 y y y,設它們的根節點分別為 p x px

px p y py py,那麼,要合併這兩個子集,只需將根節點 p x px px指向根節點 p y py py即可,如下圖所示。

程式碼模板

1)樸素並查集
此模板程式碼僅包括並查集最基本的查詢與合併操作。

// 假設共有n個節點

// 儲存每個節點的父節點
int[] p = new int[n];

// 初始化,節點編號從0開始
for(int i = 0; i < n; i ++) p[i] = i;

// 查詢操作,返回節點x的根節點,或所屬子集的編號
public int find(int x){
	// 路徑壓縮
	// 遞迴地執行這一操作:令節點x指向其父節點的父節點
	if(p[x] !=
x) p[x] = find(p[x]); return p[x]; } // 合併操作 public void union(int x, int y){ p[find(x)] = find(y); }

相關題目:

除了並查集支援的基本操作之外,根據具體的題目或應用場景,還會額外維護其它的資訊,需要在find操作和union操作的過程中同時更新該資訊。

2)維護距離的並查集
需額外維護的資訊是,每個節點到其父節點的距離,即 x x x p [ x ] p[x] p[x]的距離。這裡使用 d s t dst dst陣列來儲存每個節點到父節點的距離。

  • find(a)操作過程中如何更新dst
    find操作會進行路徑壓縮,修改節點的指向後,該節點到其父節點的距離也應該同步更新。如下圖所示,節點 a a a指向節點 b b b,節點 b b b指向節點 c c c,節點 a a a b b b到其父節點的距離分別為 d s t [ a ] dst[a] dst[a] d s t [ b ] dst[b] dst[b]。但在對節點 a a a進行find操作時,p[x] = find(p[x])會進行路徑壓縮,將節點 a a a指向節點 c c c,此時還應同時將節點 a a a到其父節點的距離更新為 d s t [ a ] ′ dst[a]^{'} dst[a],並且有 d s t [ a ] ′ = d s t [ a ] ⊕ d i s t [ b ] dst[a]^{'}=dst[a]\oplus dist[b] dst[a]=dst[a]dist[b]
    式中 ⊕ \oplus 代表廣義的加號,由距離本身的含義來決定,並不一定是 d s t [ a ] dst[a] dst[a] d s t [ b ] dst[b] dst[b]直接相加。
  • union(x, y)操作過程中如何更新dst
    假設節點 x x x的根節點為 p x px px,節點 y y y的根節點為 p y py py,union操作會將根節點 p x px px指向 p y py py,此時還應同時更新根節點 p x px px到其父節點 p y py py的距離 d s t [ p x ] dst[px] dst[px]。在查詢節點 x x x、節點 y y y的根節點時會進行路徑壓縮,同時還會更新 d s t [ x ] dst[x] dst[x] d s t [ y ] dst[y] dst[y],它們的關係如下圖所示,圖中 d x y d_{xy} dxy表示節點 x x x和節點 y y y之間的距離。結合距離所表示的具體含義,需要根據圖中所示的關係,推匯出 d s t [ p x ] dst[px] dst[px]

程式碼模板如下:

// 假設共有n個節點

// 儲存每個節點的父節點編號
int[] p = new int[p];
// 儲存每個節點到其父節點的距離
int[] dst = new int[n];

// 初始化,假設節點編號從0開始
for(int i = 0; i < n; i ++){
	p[i] = i;
	dst[i] = 0;   // 不一定是將距離初始化為0,應該根據具體問題以及距離的具體含義來決定
}

// find操作
public int find(int a){
	if(p[a] != a){
		// 記錄下節點a當前所指向的父節點的編號
		int b = p[a]
		p[a] = find(p[a]);
		// 根據具體問題以及距離的具體含義,使用dst[a]、dst[b]更新dst[a]
		dst[a] = ?
	}
	return p[a];
}

// union操作
public void union(int x, int y){
	int px = find(x);
	int py = find(y);
	if(px != py){
		p[px] = py;
		// 根據具體問題以及距離的具體含義,推匯出dst[px]
		dst[px] = ?;
	}
}

相關題目: