並查集
並查集是一個完全二叉樹,具體理解就看下面這個題吧:洛谷P1551
可以看到並查集每一個節點都存着其父親的節點。可以支持查找一個元素所屬的集合以及兩個元素各自所屬的集合的合並。可以設初始有n個元素分屬不同的集合,通過給出其中元素之間的關系,要求統計元素間的關系(就像題里面是否是親戚一樣)。這時候只需判斷元素是否屬於同一集合即可。
要實現並查集,我們可以通過一個結構體和數組來實現。
要實現並查集,我們要支持以下這些操作。
1、初始化(unionFind)一個並查集
2、把元素a和b建立聯系(uni(a,b))
3、查找a的祖先(find(x))
4、詢問a與b是否有聯系(ask(a,b))
代碼(c++)實現如下:
//並查集模板
struct uf{ int bin[10005]; //記錄父親節點的數組
uf(){ for(int i=1;i<=sizeof(bin);i++){ bin[i]=i; //初始化操作,所有元素都指向自己
} } int find(int x){ if(bin[x] != x) return find(bin[x]); else return x; //遞歸操作實現尋找 x的最終顏色
} void uni(int x,int y){ //把 x的祖先染成 y的顏色
bin[find(x)]=find(y); } bool ask(int x,int y){ //詢問操作
if(find(x) == find(y))return 1; else return 0; } };
我們會發現,在find()函數中,每次查詢都要遞歸,如果一個並查集只有根節點和左兒子,那么時間復雜度會極高,我們可以干脆把bin[x]直接指向他的祖先,這就是我們說的路徑壓縮,一般用並查集都要路徑壓縮,只需做一點小手腳就行了。
代碼如下:
//路徑壓縮
int find(int x){ if(bin[x] != x) return bin[x]=find(bin[x]); else return x; }
通過路徑壓縮,可以有效地降低時間復雜度。