Disjoint Set Union (DSU)
- 2021.11.29
- Disjoint Set Union
為 disjoint (non-overlapping) sets 設計的資料結構
演算法
Time Complexity: O(node 的數量)
Space Complexity: O(node 的數量)
使用「秩(rank)」能在連結兩元素時所建立的樹較為平均
「秩(rank)」的定義如下:
- 只有根節點的樹(即只有一個元素的集合),秩為0
- 當兩棵秩不同的樹合併後,新的樹的秩為原來兩棵樹的秩的較大者;
- 當兩棵秩相同的樹合併後,新的樹的秩為原來的樹的秩加一。
添加元素
def make_set(x): x.root = x
使用「秩」
def make_set(x): x.root = x x.rank = 0
查找元素
def find(x):
  if x.root == x:
    return x
  x.root = find(x.root)
  return x.root
連結兩元素
def union(x, y):
  x_root = find(x)
  y_root = find(y)
  if x_root != y_root:
    x_root.root = y_root
使用「秩」
def union(x, y): 
  x_root = find(x) 
  y_root = find(y) 
  if x_root != y_root: 
    if x_root.rank < y_root.rank:
      large = y_root
      small = x_root 
    else:
      large = x_root 
      small = y_root
    
    small.root = large
    if large.rank = small.rank:
      large.rank += 1
包裝成 class
Python
無秩
class Dsu:
  def __init__(self, roots = None):
    self.root = {}
    if roots:
      for r in roots:
        self.make_set(r)
  def make_set(self, x): 
    self.root[x] = x
  def find(self, x):
    if self.root[x] == x:
      return x
    self.root[x] = self.find(self.root[x])
    return self.root[x]
  def union(self, x, y): 
    x_root = self.find(x) 
    y_root = self.find(y) 
    if x_root != y_root: 
      self.root[x_root] = y_root
  def are_in_same_set(self, x, y):
    return self.find(x) == self.find(y)
  def get_ds(self): # get disjoint sets
    disjoint_sets = collections.defaultdict(set)
    for key in self.root:
      disjoint_sets[self.find(key)].add(key)
    return disjoint_sets
有秩
class Dsu:
  def __init__(self, roots = None):
    self.root = {}
    self.rank = {}
    if roots:
      for r in roots:
        self.make_set(r)
  def make_set(self, x): 
    self.root[x] = x
    self.rank[x] = 0
  def find(self, x):
    if self.root[x] == x:
      return x
    self.root[x] = self.find(self.root[x])
    return self.root[x]
  def union(self, x, y): 
    x_root = self.find(x) 
    y_root = self.find(y) 
    if x_root != y_root: 
      if self.rank[x_root] < self.rank[y_root]:
        large = y_root
        small = x_root 
      else:
        large = x_root 
        small = y_root
    
      self.root[small] = large
      if self.rank[large] == self.rank[small]:
        self.rank[large] += 1
  def are_in_same_set(self, x, y):
    return self.find(x) == self.find(y)
  def get_ds(self): # get disjoint sets
    disjoint_sets = collections.defaultdict(set)
    for key in self.root:
      disjoint_sets[self.find(key)].add(key)
    return disjoint_sets
Ref: Wikipedia
經典例題
- Leetcode # 200. Number of Islands
- Leetcode # 305. Number of Islands II
- Leetcode # 323. Number of Connected Components in an Undirected Graph
Last Updated on 2023/08/16 by A1go
 
	
           
  