union/find--不相交集合

前言

你們好,今天提供不相交集合的筆記(即union/find). 不相交集合有實現簡單,證實困難的特色,如有想證實的能夠自行查閱相關文獻。我就不作贅述啦!java

用途

不相交集類解決動態等價類問題,即:git

  1. 查找find一個元素屬於哪一個等價類
  2. 合併union 兩個等價類爲一個新的等價類。
    也就是常說的union/find算法

基本概念介紹

等價類定義

  1. 一個元素a屬於S的等價類是S的一個子集合,它包含全部與a有等價關係的元素。
  2. 等價類對S進行劃分:S中的每個成員剛好出如今一個等級類中。

等價關係定義

  1. 自反性 a屬於S,aRa (R表明關係)
  2. 對稱性 aRb,bRa
  3. 傳遞性 aRb,bRc則 aRc

舉例

  1. 「>」號不是等價關係,沒有對稱性
  2. 電器連通性是等價關係

基本數據結構

數據結構須要良好支持union和find操做,union操做相對簡單,咱們關注find操做。github

find操做的特色及分析

find操做只要求當且僅當兩個元素屬於同一個集合時,做用在這兩個元素上的find返回相同的集合名稱。 由此天然想到: 由於樹的每個元素都有相同的根,因此等價類能夠用樹表示,不相交集則以森林表示。樹的根存儲集合名稱。 依照上述假設: find操做實質從指定節點向上找到根,因此只須要保存父鏈算法

可行數據結構(非惟一)

因爲只需保存父鏈,不相交集類(森林)中的等價類(樹)能夠被非顯示的存儲在數組中,數組中元素有以下約定:數組

  1. 數組中每一個成員s[i]表示元素i的父親,
  2. 若是i是根,那麼s[i]=-1.

圖示說明

下圖是隱示的森林示意圖,上邊是隱示森林數組,下邊是依據該數組展示實際的森林。 隱示的森林示意圖數據結構

按秩求並

爲何要使用?

任意合併會出現過深的樹,因此採用按秩求並,它保證樹的深度不超過O(logN)3d

如何實現?

  1. 初始時爲-1,
  2. 僅當兩顆相等深度的樹求並時秩才增長;增長秩的操做實際爲當前值-1

代碼示意

/**
 * 採用按秩求並
 * @param root1 不相交集合1的根
 * @param root2 不相交集合2的根
 */
public void union(int root1, int root2) {
	if(s[root2]<s[root1]){
		s[root1]=root2;
	}else{
	  if(s[root1]==s[root2]){
		s[root1]--;
	  }
		s[root2]=root1;
	}
}

圖例說明

按秩求並

路徑壓縮

爲何要使用?

不進行路徑壓縮,M次操做,容易出現最差狀況O(MlogN),其中N爲節點個數code

如何實現?

  1. 路徑壓縮用於find與union無關
  2. 設操做find(x),此時路徑壓縮的效果是:
    從x到根的路徑上的每一個節點都使其父節點爲該樹的根

代碼示意

/**
  * 查找方式 :路徑壓縮
  * @param x 要尋找的元素
  * @return x屬於的集合
  */
public int find(int x) {
	if (s[x] < 0) {
		return x;
	} else {
		return s[x] = find(s[x]);
	}
}

圖例說明

路徑壓縮

理論界限

M次union和find的運行時間爲:blog

O(Mlog*N)

寫在最後

什麼你以爲太簡單了,建議你試着證實! 什麼代碼沒有難度,能夠實現各迷宮試試啊!get

相關代碼地址

完整代碼地址:https://github.com/floor07/DataStructuresAndAlgorithm/blob/master/src/main/java/chapter8/DisjSets.java

參考他人實現編寫的迷宮:https://github.com/floor07/DataStructuresAndAlgorithm/blob/master/src/main/java/chapter8/Maze.java

相關文章
相關標籤/搜索