java——並查集 UnionFind
阿新 • • 發佈:2018-11-02
時間複雜度:
O(log*n),近乎是O(1)級別的
UnionFind 介面:
public interface UF { int getSize(); boolean isConnected(int p, int q); void unionElements(int p, int q); }
第一種:
//quickFind public class UnionFind1 implements UF{ //id 這個陣列中並沒有儲存資料的值,而是儲存了資料所在的集合編號 private int[] id; publicUnionFind1(int size) { id = new int[size]; for(int i = 0 ; i < id.length ; i ++) { id[i] = i; } } @Override public int getSize() { return id.length; } //查詢元素p所對應的集合編號 private int find(int p) { if(p < 0 || p >= id.length) {throw new IllegalArgumentException("p is out of bound."); } return id[p]; } //檢視元素p和q是否屬於同一個集合 @Override public boolean isConnected(int p, int q) { // TODO Auto-generated method stub return find(p) == find(q); } //將p和q所屬的集合合併 @Overridepublic void unionElements(int p, int q) { // TODO Auto-generated method stub 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; } } } }
第二種:
//QuickUnion //一種孩子指向父親節的樹 public class UnionFind2 implements UF{ private int[] parent; public UnionFind2(int size) { parent = new int[size]; //初始的時候每一個節點都指向他自己,每一個節點都是一棵獨立的樹 for(int i = 0 ; i< size ; i ++) { parent[i] = i; } } @Override public int getSize() { return parent.length; } private int find(int p) { if(p < 0 || p >= parent.length) { throw new IllegalArgumentException("p is out of bound."); } while(p != parent[p]) { p = parent[p]; } return p; } @Override public boolean isConnected(int p, int q) { return find(p) == find(q); } @Override public void unionElements(int p, int q) { int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) { return; }else { parent[pRoot] = qRoot; } } }
第三種:
package UnionFind; //使樹的深度儘量保持較低水平 //節點總數小的那個樹去指向節點總數大的那棵樹 public class UnionFind3 implements UF { private int[] parent; // sz[i]表示以i為根的的集合中元素的個數 private int[] sz; public UnionFind3(int size) { parent = new int[size]; for(int i = 0 ; i < parent.length ; i ++) { parent[i] = i; sz[i] = 1; } } @Override public int getSize() { // TODO Auto-generated method stub return parent.length; } private int find(int p) { if(p < 0 || p >= parent.length) { throw new IllegalArgumentException("p is out of bound."); } while(p != parent[p]) { p = parent[p]; } return p; } @Override public boolean isConnected(int p, int q) { return find(p) == find(q); } @Override public void unionElements(int p, int q) { int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) { return; } if(sz[pRoot] < sz[qRoot]) { parent[pRoot] = qRoot; sz[qRoot] += sz[pRoot]; }else { parent[qRoot] = pRoot; sz[pRoot] += sz[qRoot]; } } }
第四種:
//基於rank的優化 //使深度小的那棵樹指向深度大的那棵樹 public class UnionFind4 implements UF { private int[] parent; // rank[i]表示以i為根的的集合所表示的樹的層數 private int[] rank; public UnionFind4(int size) { parent = new int[size]; for(int i = 0 ; i < parent.length ; i ++) { parent[i] = i; rank[i] = 1; } } @Override public int getSize() { // TODO Auto-generated method stub return parent.length; } private int find(int p) { if(p < 0 || p >= parent.length) { throw new IllegalArgumentException("p is out of bound."); } while(p != parent[p]) { p = parent[p]; } return p; } @Override public boolean isConnected(int p, int q) { return find(p) == find(q); } @Override public void unionElements(int p, int q) { int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) { return; } if(rank[pRoot] < rank[qRoot]) { parent[pRoot] = qRoot; }else if(rank[pRoot] > rank[qRoot]){ parent[qRoot] = pRoot; }else { parent[qRoot] = pRoot; rank[pRoot] += 1; } } }
第五種:
//路徑壓縮 public class UnionFind5 implements UF{ private int[] parent; // rank[i]表示以i為根的的集合所表示的樹的層數 private int[] rank; public UnionFind5(int size) { parent = new int[size]; for(int i = 0 ; i < parent.length ; i ++) { parent[i] = i; rank[i] = 1; } } @Override public int getSize() { // TODO Auto-generated method stub return parent.length; } //這裡新增路徑壓縮的過程 private int find(int p) { if(p < 0 || p >= parent.length) { throw new IllegalArgumentException("p is out of bound."); } while(p != parent[p]) { parent[p] = parent[parent[p]]; p = parent[p]; } return p; } @Override public boolean isConnected(int p, int q) { return find(p) == find(q); } //這裡的rank不再是每個節點精準的深度,只是做為一個參考,由於效能考慮所以不維護rank @Override public void unionElements(int p, int q) { int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) { return; } if(rank[pRoot] < rank[qRoot]) { parent[pRoot] = qRoot; }else if(rank[pRoot] > rank[qRoot]){ parent[qRoot] = pRoot; }else { parent[qRoot] = pRoot; rank[pRoot] += 1; } } }
第六種:
//find過程中讓每個節點都指向根節點 //路徑壓縮 public class UnionFind6 implements UF{ private int[] parent; // rank[i]表示以i為根的的集合所表示的樹的層數 private int[] rank; public UnionFind6(int size) { parent = new int[size]; for(int i = 0 ; i < parent.length ; i ++) { parent[i] = i; rank[i] = 1; } } @Override public int getSize() { // TODO Auto-generated method stub return parent.length; } //這裡新增路徑壓縮的過程 //遞迴呼叫 private int find(int p) { if(p < 0 || p >= parent.length) { throw new IllegalArgumentException("p is out of bound."); } if(p != parent[p]) { parent[p] = find(parent[p]); } return parent[p]; } @Override public boolean isConnected(int p, int q) { return find(p) == find(q); } //這裡的rank不再是每個節點精準的深度,只是做為一個參考,由於效能考慮所以不維護rank @Override public void unionElements(int p, int q) { int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) { return; } if(rank[pRoot] < rank[qRoot]) { parent[pRoot] = qRoot; }else if(rank[pRoot] > rank[qRoot]){ parent[qRoot] = pRoot; }else { parent[qRoot] = pRoot; rank[pRoot] += 1; } } }