並查集2個優化——按秩合並和路徑壓縮


並查集有兩個優化。

一、按秩合並

描述:就是在對兩個不同子集連接時,按照rank來連,也就是rank低的連在rank高的下面。rank高的做父親節點。

作用,這樣類似維護了一棵樹,樹是rank高的在上。

 

// 初始化n個元素
void init(int n)
{
    for(int i=0;i<n;i++)
    {
        parent[i]=i;
        rank[i]=0;   // 初始樹的高度為0
    }
}


// 合並x和y所屬的集合
void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y) return ;
    if(rank[x]<rank[y])
        parent[x]=y;  // 合並是從rank小的向rank大的連邊
    else
    {
        parent[y]=x;
        if(rank[x]==rank[y]) rank[x]++;
    }
}

 

二、路徑壓縮

描述:假如fa數組已經嵌套了N層,那么傳統的做法去找祖先要做N次,當N很大時,這種做法很沒效率。

這是朴素查找的代碼,適合數據量不大的情況

int findx(int x) { int r=x; while(parent[r] !=r) r=parent[r]; return r; }

    下面是采用遞歸路徑壓縮的方法查找元素,但是,遞歸壓縮路徑可能會造成溢出棧會發生RE

int find(int x) //查找x元素所在的集合,回溯時壓縮路徑 { if (x != parent[x]) { parent[x] = find(parent[x]); //回溯時的壓縮路徑  } //從x結點搜索到祖先結點所經過的結點都指向該祖先結點  return parent[x]; }

 

下面我們說一下非遞歸方式進行的路徑壓縮

int find(int x) { int k, j, r; r = x; while(r != parent[r]) //查找跟節點  r = parent[r]; //找到跟節點,用r記錄下  k = x; while(k != r) //非遞歸路徑壓縮操作  { j = parent[k]; //用j暫存parent[k]的父節點  parent[k] = r; //parent[x]指向跟節點  k = j; //k移到父節點  } return r; //返回根節點的值  }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM