並查集學習筆記

$\Huge\text{並查集學習筆記}$
並查集是一種用於查詢兩個元素是否在統一集合內或者合併兩個集合的數據結構,十分重要!!
並查集,在一些有N個元素的集合應用問題中,咱們一般是在開始時讓每一個元素構成一個單元素的集合,而後按必定順序將屬於同一組的元素所在的集合合併,其間要反覆查找一個元素在哪一個集合中。這一類問題近幾年來反覆出如今信息學的國際國內賽題中,其特色是看似並不複雜,但數據量極大,若用正常的數據結構來描述的話,每每在空間上過大,計算機沒法承受;即便在空間上勉強經過,運行的時間複雜度也極高,根本就不可能在比賽規定的運行時間(1~3秒)內計算出試題須要的結果,只能用並查集來描述。
並查集是一種樹型的數據結構,用於處理一些不相交集合(Disjoint Sets)的合併及查詢問題。經常在使用中以森林來表示。(摘自百度百科
並查集須要支持兩種操做
先來看一下圖:

1.查詢$\text{find(x)}$(查詢$x$所在集合的表明元素)
直接看圖

下面是查詢的代碼數組

int find (int x){
    return fa[x]==x?x:find(fa[x]);
}

$fa$數組用於存儲$x$元素所在集合的表明元素。在一開始每一個元素的都是單獨的因此$\text{fa[x]=x}$
2合併$\text{Union(x,y)}$(將$x$所在的集合與$y$所在的集合)
直接看圖

下面是合併的代碼數據結構

void Union(int x,int y){
    fa[find(x)]=find(y);
    return;
}

將$x$所在集合的表明元素更改成$y$所在集合的表明元素
以上就是並查集的兩種基本操做。
並查集的兩種優化方式:
1.路徑壓縮
並查集合並完以後造成了一棵樹,以下圖

這種方法在查詢時可能會被卡死,以下圖左邊(樹變成了一條鏈!!!)

被卡成一條鏈以後,$find$操做會變得很是慢,路徑壓縮就解決了這種狀況優化成了上圖右邊的樣子
作法就是直接把元素連向該集合的表明元素而不是連接別的元素別的元素再去連接表明元素。
下面是路徑壓縮的代碼學習

int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}

$\large\text{注意有時候不能使用路徑壓縮如P2661信息傳遞}$
2.按秩合併
按秩合併就是將高度(或大小)曉得一棵樹連到高度深的一棵樹下面以下圖

下面是按秩合併(高度)的代碼優化

void Union(int x,int y){
    int rootx=find(x),rooty=find(y);
    if(rootx==rooty) return;
    if(r[rootx]<r[rooty]) fa[rootx]=rooty;
    else if(r[rootx]>r[rooty]) fa[rooty]=rootx;
    else{
        fa[rootx]=rooty;
        r[rooty]++;
    }
}

下面是按秩合併(大小)的代碼code

void Union(int x,int y){
    int rootx=find(x),rooty=find(y);
    if(rootx==rooty) return;
    if(size[rootx]>size[rooty]){
        fa[rooty]=rootx;
        size[rootx]+=size[rooty];
    }else{
        fa[rootx]=rooty;
        size[rooty]+=size[rootx];
    }
}

$r$數組用於記錄樹的高度,$size$數組用於記錄樹的大小。
基本的並查集就是以上說的那些,本博客的圖片來源於簡書blog

相關文章
相關標籤/搜索