# Union-Find source: [Coursera Algorithms, Part 1](https://www.coursera.org/learn/algorithms-part1) Algorithms, 4th ed. - [Sedgewick, Wayne] --- ## 什麼是 Union-Find - 尋找一批 object 中的任兩個 object 是否在同一群 - 同一群的 object 間,有路可以找到彼此 - 路表示 object 之間的連結 - 兩個不同群的 object 間,找不到路可以通到對方 --- ## 為什麼要知道 Union-Find - 應用環境 - 圖片畫素 - 網路節點 - 社交軟體的朋友關係 - 電路晶體 - ... --- ## Union(連結)的建立 - 每個 object 都給一個編號 - 假設有 N 個 object ,編號從 0~N-1 - 用 connect(a, b) 表示連結編號 a 和編號 b - ex: connect(3, 10) 表示連結 object 3 和 object 10 --- ## 如何判斷在同一群 - 儲存連結的方式影響判斷的速度 - list - 有關係的 object 串在同一個list中 - 判斷兩個 object 是否在同一個list中 - array - 每個 object 都有一個標籤 - 判斷兩個 object 的標籤一不一樣 - array 比較快,因為只要比較一次 (quick-find) --- ## 如何用array儲存 - 建立 array - 標籤建立時使用對應 object 的編號 | object | 0 | 1 | 2 | ... | N-1 | |- |- |- |- |- |- | |標籤 | 0 | 1 | 2 | ... | N-1 | --- <!-- .slide: style="text-align: left;" --> ## 如何用array儲存 - 建立連結 - 連結在一起的 object 把標籤改成一樣 - 假設改成跟第二個 object 一樣 - connect(1,3) | object | 0 | 1 | 2 | 3 | |- |- |- |- |- | |標籤 | 0 | <font color="red">3</font> | 2 | 3 | - connect(3,2) | object | 0 | 1 | 2 | 3 | |- |- |- |- |- | |標籤| 0 | <font color="red">2</font> | 2 | <font color="red">2</font> | --- ## 成本 - 讀寫 array 的次數 - 連結兩個 object 時就要把整個 array 走一次,才能確保該改的標籤都有改到 - 若是對 $N$ 個 object 做 $N$ 次連結,就需要 $N^2$ 次讀寫 - **Slow!** |方法|建立 |連結 |判斷 | |- |- |- |- | | quick-find | $N$ | $N$ | $1$ | --- ## 改進 - 連結成本 - 用樹狀的方式連結 (quick-union) - 標籤改成代表 parent object --- - object 標籤與 object 編號一樣時表示 object 是一個 root - 連結兩個 object 等於把兩個 object 所在的 tree 合併成一個 tree --- ## 樹狀 array - 建立 - 標籤建立時每個 object 就是一個 root | object | 0 | 1 | 2 | ... | N-1 | |- |- |- |- |- |- | |標籤 | 0 | 1 | 2 | ... | N-1 | --- <!-- .slide: style="text-align: left;" --> ## 樹狀 array - 連結 - 假設使用第二個 object 的 root 當作新的 root --- <!-- .slide: style="text-align: left;" --> - connect(1,3) | object | 0 | 1 | 2 | 3 | 4 | |- |- |- |- |- |- | |標籤 | 0 | <font color="red">3</font> | 2 | 3 | 4 | - connect(0,4) | object | 0 | 1 | 2 | 3 | 4 | |- |- |- |- |- |- | |標籤 | <font color="red">4</font> | 3 | 2 | 3 | 4 | --- <!-- .slide: style="text-align: left;" --> - connect(1,0) - object 1 root = object 3 - object 0 root = object 4 | object | 0 | 1 | 2 | 3 | 4 | |- |- |- |- |- |- | |標籤 | 4 | 3 | 2 | <font color="red">4</font> | 4 | --- ## 成本 - 最差的情況下樹的深度可能跟 object 數量一樣 - unbalanced tree - 連結時找 root 的讀寫次數與深度有關 - 最多 $N$ 次 - 以 object root 是否相同判斷有沒有在同一群 - 也跟樹的深度相關 - 最多 $N$ 次 --- <!-- .slide: style="text-align: left;" --> - **Slow too!** |方法|建立 |連結 |判斷 | |- |- |- |- | | quick-find | $N$ | $N$ | $1$ | | quick-union| $N$ | $N$ | $N$ | --- ## 改進 - 避免樹長太深 - 紀錄樹的深度 (weighted quick-union(QU)) - 連結時把矮的樹並到高的樹中 - 減緩樹變深的速度 ![](https://i.imgur.com/TKRcyLp.png) --- - 樹的深度最多是 $log_2N$ - 為什麼? --- ## 原因 - 要讓 tree x 深度+1,tree x 就必須跟<font color="red">至少跟自己一樣長</font>的 tree y 合併 - 深度每+1,樹包含的 <font color="red">object 數量就 double</font> - $N$ 個 object 最多只能 double <font color="red">$log_2N$</font> 次 --- ## 成本 |方法|建立 |連結 |判斷 | |- |- |- |- | | quick-find | $N$ | $N$ | $1$ | | quick-union| $N$ | $N$ | $N$ | | weighted QU| $N$ | $log_2N$ | $log_2N$ | --- ## 改進 - 讓樹更扁 - 找 object 的 root 時,順手把所有經過的 object 都往上提兩層 (path compression) - 把 parent object 改成 grand parent object - 找到 root 後,原本 object 所在的深度就會減半 --- ## 成本 - 專家說會變成 $Nlog_2^*N$ - $log_2^*N$ = 對 $N$ 重複做 $log_2$ 到 $\leq1$ 的次數 ([Iterated logarithm](https://en.wikipedia.org/wiki/Iterated_logarithm)) - $log_2^*65536$ = 4 - $log_265536=16$, $log_216=4$, $log_24=2$, $log_22=1$ --- |方法|建立 |連結 |判斷 | |- |- |- |- | | quick-find | $N$ | $N$ | $1$ | | quick-union| $N$ | $N$ | $N$ | | weighted QU (WQU)| $N$ | $log_2N$ | $log_2N$ | | WQU & path compression| $N$ | $log_2^*N$ | $log_2^*N$ |