數據結構——並查集
阿新 • • 發佈:2019-02-05
技術 bool 數組 用戶 span pen main 就是 set
並查集,是我目前為止見過的,實現起來最淳樸的數據結構,但是功能也很強大。
並查集核心由三個數組和兩個函數構成。
數組pre[ ]記錄了每個點的前導點是什麽,數組data[ ]記錄數據,數組size[ ]記錄每個點包含節點(自己和所有下級節點)的個數。
函數find是查找某個節點,返回該節點的最終前導;
函數union是將給的兩個節點所在的集合 合並。
對於查找操作,假設需要確定x所在的的集合,也就是確定集合的代表元。可以沿著pre[x]不斷在樹形結構中向上移動,直到到達根節點。為了加快查找速度,在查找過程中可以實現路徑壓縮:
//查找 int Find(int x) { if(pre[x] == x)return x; //用哪一個在於是否需要壓縮路徑 //return pre[x] = Find(pre[x]); return Find(pre[x]); }
這是並查集的合並,實際運用中具體合並方法還是要看題目的。
//合並 void Union(int x, int y) { int fx = Find(x), fy = Find(y); if (fx == fy) return; //fx的深度大於fy的話,把fy掛上去,不會增加rank if (rank[fx] > rank[fy]) pre[fy]= fx; else { if (rank[fx] == rank[fy])rank[fy] ++; pre[fx] = fy; } }
完成實現代碼:
int pre[1000]; int data[1000]; int rank[1000]; //對n個節點進行初始化 void init(int *a, int n) { for (int i = 0; i < n; i++) { //這裏接收用戶輸入時直接輸入進來更好 data[i] = a[i]; pre[i] = i; rank[i]View Code= 1; } } //查找 int Find(int x) { if (pre[x] == x)return x; return pre[x] = Find(pre[x]); } //合並 void Union(int x, int y) { int fx = Find(x), fy = Find(y); if (fx == fy) return; //fx的深度大於fy的話,把fy掛上去,不會增加rank if (rank[fx] > rank[fy]) pre[fy] = fx; else { if (rank[fx] == rank[fy])rank[fy] ++; pre[fx] = fy; } } //判斷兩個結點,是否位於同一集合 bool IsSameSet(int x, int y) { return Find(x) == Find(y); }
OJ練習:
HDU 1232 :http://acm.hdu.edu.cn/showproblem.php?pid=1232
基本思想是:N個節點,最少需要N-1根線連起來。
把輸入的城鎮全部進行Union,如果這兩個城鎮不連通,N--,最後輸出N-1就是答案,其實比上面實現的並查集結構更簡單,只需要一個Pre數組就可以了。
#include<stdio.h> int Pre[1001]; //查找 int Find(int x) { if (Pre[x] == x)return x; return Pre[x] = Find(Pre[x]); } //合並 void Union(int x, int y, int &n) { int fx = Find(x), fy = Find(y); if (fx == fy) return; Pre[fx] = fy; n--; } int main() { int n, m; while (~scanf("%d", &n)) { if (n == 0) break; //這裏註意不要寫成i<n了,-_- for (int i = 0; i <= n; i++) Pre[i] = i; scanf("%d", &m); while (m--) { int c1, c2; scanf("%d%d", &c1, &c2); Union(c1, c2, n); } printf("%d\n", n - 1); } return 0; }
HDU 1879 :http://acm.hdu.edu.cn/showproblem.php?pid=1879
數據結構——並查集