上一章我大概說明了什麼是圖論以及無向圖的基礎概念,本章咱們要研究一種更廣泛的算法——連通性算法。它屬於圖論的分支,也是一種抽象算法。在深刻算法以前,咱們先提出一個具體的問題:假設在空間中存在N個點,咱們能夠經過線段鏈接任意兩點,相互鏈接的點屬於同一組連通份量,咱們如何計算點p和點q之間是否連通。算法的核心是:如何表示連通性以及如何檢查連通性。算法
下面提供算法的抽象接口:數組
/** * 連通性算法 */ public interface UnionFind { /** * p點和q點之間添加一條通路 * * @param p * @param q */ void union(int p, int q); /** * 獲取p點的連通份量 * * @param p * @return */ int find(int p); /** * 判斷p點和q點是否存在一條通路 * * @param p * @param q * @return */ boolean connected(int p, int q); /** * 連通份量的數量 * * @return */ int count(); }
1、快速查詢算法Quick-Findide
咱們將空間中的點這一律念抽象成int[](整形數組),i表明不一樣的點int[i]表明不一樣的連通份量。一種比較容易理解的想法是,從屬於同一組連通份量的任一點p和q一定int[p]等於int[q]。所以當咱們須要查詢點p和q是否連通的時候只須要判斷int[p] == int[q]是否成當即可。學習
/** * 連通性算法:quick-find */ public class QuickFind implements UnionFind { private int[] id; // 份量id private int count; public QuickFind(int n) { count = n; id = new int[n]; for (int i = 0; i < n; i++) { id[i] = i; } } @Override public void union(int p, int q) { int pID = find(p); int qID = find(q); if(pID == qID) { return; } for(int i = 0;i < id.length; i++) { if(id[i] == pID) { id[i] = qID; } } count--; } @Override public int find(int p) { return id[p]; } @Override public boolean connected(int p, int q) { return find(p) == find(q); } @Override public int count() { return count; } }
find()操做的速度顯然是很快的,由於它只須要訪問id[]數組一次。可是對於每一對數組union()都須要掃描整個id[]數組。所以quick-find算法通常沒法處理大型數組。ui
算法圖示:spa
2、快速鏈接算法Quick-Unioncode
咱們要討論的下一個算法的重點是提升union()方法的速度,爲此可能會稍微犧牲一下find()的效率,可是一般狀況下這樣作是值得的。Quick-Union算法考慮把屬於同一組連通份量的點鏈接成一棵樹,i表明點,int[i]表明i的父節點,根節點p等於int[p]。blog
public class QuickUnion implements UnionFind { private int count; private int[] id; public QuickUnion(int n) { count = n; id = new int[n]; for(int i = 0; i < n; i++) { id[i] = i; } } @Override public void union(int p, int q) { int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) { return; } id[pRoot] = qRoot; count--; } @Override public int find(int p) { while(p != id[p]) { p = id[p]; } return p; } @Override public boolean connected(int p, int q) { return false; } @Override public int count() { return 0; } }
快速鏈接算法的每一次鏈接會分別遍歷兩次連通份量,在連通份量中包含元素數量相對總數而言比較小的狀況下能夠提供很是不錯的速度。接口
算法圖示:io
事實上,不管是Quick-Find算法仍是Quick-Union算法,他們在圖論的基礎上基本是起到相互補充的做用。更重要的一點是,咱們經過對他們的學習能夠認識到,十全十美的算法很難實現,更多的時候算法針對某一個問題的痛點纔是有效的。