日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

并查集简单使用

發(fā)布時間:2025/4/5 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并查集简单使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

      • 并查集--判斷圖上是否有環(huán)
      • Leetcode冗余鏈接
      • Leetcode島嶼數(shù)量
      • 牛客網(wǎng)-找朋友

啥是并查集?

并查集是用來合并不相交集合的數(shù)據(jù)結(jié)構(gòu),一個常用的地方是判斷圖上是否有環(huán)。

并查集–判斷圖上是否有環(huán)

下面這幅圖中有環(huán),如何判斷是否有圖?判斷兩個集合中元素是否有共同樹根。

分成兩個集合A和B
對于集合A,取1為樹根;對于集合B,取3為樹根。如果(1,3)之間有邊,則A和B是構(gòu)成一個集合。這時候A,B中的任意兩個頂點之間存在邊,,如(2,4)之間存在邊,就說明該圖有環(huán)。

步驟

  • 初始化:根節(jié)點數(shù)組parent [ ] 初始化為-1,表示都是獨立的節(jié)點
  • 尋根 find_root()
  • 合并union_vertices()
  • 下面是沒有按秩合并的代碼,容易使得樹的高度過高。
    代碼

    //找根節(jié)點 int find_root(int x ,int parent[]) {int x_root =x;while(parent[x_root]!=-1){x_root=parent[x_root];}return x_root; } //合并 int union_vectices(int x,int y,int parent[]){int x_root=find(x,parent);int y_root=find(y,parent);if(x_root==y_root) return 0;else{parent[x_root]=y_root;//強行x的根節(jié)點設(shè)為yreturn 1;} }

    測試

    int main(){int parent[VERTICES]={0};initialise(parent);int edges[6][2]={//六條邊 {0,1},{1,2},{1,3},{2,4},{2,5},{3,4}};for(int i=0;i<6;i++){//六條邊 int x=edges[i][0];int y=edges[i][1];if(union_vertices(x,y,parent)==0){cout<<"cycle detected"<<endl;exit(0);} }cout<<"No cycles found"<<endl;}

    上述沒有按秩合并

    按秩合并需要引入數(shù)的高度數(shù)組rank [ ],記錄樹的高度,原則是 矮的樹掛到高的樹上。

    壓縮路徑之后的Union_vertices()函數(shù)

    int union_vertices(int x,int y,int parent[],int rank[]){int x_root=find_root(x,parent);int y_root=find_root(y,parent);if(x_root==y_root) return 0;else{if(rank[x_root]>rank[y_root])parent[y_root]=x_root;else if(rank[x_root]<rank[y_root])parent[x_root]=y_root;else{//樹高相同parent[x_root]=y_root;rank[y_root]++; }return 1;} }

    完整并查集測試代碼

    #include<iostream> #include<cstdlib> using namespace std; #define VERTICES 6void initialise(int parent[],int rank[]){int i;for(int i=0;i<VERTICES;i++){parent[i]=-1;//表示獨立節(jié)點 rank[i]=0;} } int find_root(int x ,int parent[]) {int x_root =x;while(parent[x_root]!=-1){x_root=parent[x_root];}return x_root; }int union_vertices(int x,int y,int parent[],int rank[]){int x_root=find_root(x,parent);int y_root=find_root(y,parent);if(x_root==y_root) return 0;else{if(rank[x_root]>rank[y_root])parent[y_root]=x_root;else if(rank[x_root]<rank[y_root])parent[x_root]=y_root;else{parent[x_root]=y_root;rank[y_root]++; }return 1;} }int main(){int parent[VERTICES]={0};int rank[VERTICES]={0}; initialise(parent,rank);int edges[6][2]={//六條邊 {0,1},{1,2},{1,3},{2,4},{2,5},{3,4}};for(int i=0;i<6;i++){//六條邊 int x=edges[i][0];int y=edges[i][1];if(union_vertices(x,y,parent,rank)==0){cout<<"Cycle detected"<<endl;exit(0);} }cout<<"No cycles found"<<endl;}

    該測試代碼檢測上述圖中是否有環(huán)

    下面附上一道Leetcode題目

    Leetcode冗余鏈接

    在本問題中, 樹指的是一個連通且無環(huán)的無向圖。

    輸入一個圖,該圖由一個有著N個節(jié)點 (節(jié)點值不重復(fù)1, 2, …, N) 的樹及一條附加的邊構(gòu)成。附加的邊的兩個頂點包含在1到N中間,這條附加的邊不屬于樹中已存在的邊。

    結(jié)果圖是一個以邊組成的二維數(shù)組。每一個邊的元素是一對[u, v] ,滿足 u < v,表示連接頂點u 和v的無向圖的邊。

    返回一條可以刪去的邊,使得結(jié)果圖是一個有著N個節(jié)點的樹。如果有多個答案,則返回二維數(shù)組中最后出現(xiàn)的邊。答案邊 [u, v] 應(yīng)滿足相同的格式 u < v。

    示例 1:

    輸入: [[1,2], [1,3], [2,3]]
    輸出: [2,3]
    解釋: 給定的無向圖為:

    1/ \ 2 - 3

    示例 2:
    輸入: [[1,2], [2,3], [3,4], [1,4], [1,5]]
    輸出: [1,4]
    解釋: 給定的無向圖為:

    5 - 1 - 2| |4 - 3

    注意:
    輸入的二維數(shù)組大小在 3 到 1000。
    二維數(shù)組中的整數(shù)在1到N之間,其中N是輸入數(shù)組的大小。

    代碼
    分為兩部分,上面是并查集原封不動,下面是調(diào)用Union函數(shù)來進(jìn)行判斷是否有環(huán)。

    class UnionFindSet{ public://初始化UnionFindSet(int n){ranks_=vector<int>(n+1,0);parents_=vector<int>(n+1,0);for(int i=0;i<parents_.size();++i)parents_[i]=i;}//根節(jié)點int Find(int u){//優(yōu)化1-壓縮路徑if(u!=parents_[u])parents_[u]=Find(parents_[u]);return parents_[u];}//合并集合bool Union(int u ,int v){int pu=Find(u);int pv=Find(v);if(pu==pv) return false;//有環(huán)//優(yōu)化2-按秩合并if(ranks_[pu]<ranks_[pv])parents_[pu]=pv;else if(ranks_[pu]>ranks_[pv])parents_[pv]=pu;else{parents_[pv]=pu;ranks_[pu]++;}return true;} private:vector<int> parents_;vector<int> ranks_; };class Solution { public:vector<int> findRedundantConnection(vector<vector<int>>& edges) {UnionFindSet s(edges.size());for(const auto edge: edges){//基于范圍for循環(huán)if(!s.Union(edge[0],edge[1]))//調(diào)用Union函數(shù)return edge;}return {};} };

    來源:力扣(LeetCode)
    鏈接:https://leetcode-cn.com/problems/redundant-connection
    著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有。商業(yè)轉(zhuǎn)載請聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

    Leetcode 200

    Leetcode島嶼數(shù)量

    給你一個由 ‘1’(陸地)和 ‘0’(水)組成的的二維網(wǎng)格,請你計算網(wǎng)格中島嶼的數(shù)量。

    島嶼總是被水包圍,并且每座島嶼只能由水平方向和/或豎直方向上相鄰的陸地連接形成。

    此外,你可以假設(shè)該網(wǎng)格的四條邊均被水包圍。

    示例 1:

    輸入:
    11110
    11010
    11000
    00000
    輸出: 1

    示例 2:

    輸入:
    11000
    11000
    00100
    00011
    輸出: 3
    解釋: 每座島嶼只能由水平和/或豎直方向上相鄰的陸地連接而成。
    分析
    并查集解法
    合并時,判斷左邊和上邊位置。不需要判斷下邊和右邊。

    代碼

    class Solution { public:vector<int> parents_;vector<int> ranks_;int find(int x){if(x!=parents_[x])parents_[x]=find(parents_[x]);return parents_[x];}void Union(int x, int y){int fx=find(x);int fy=find(y);if(ranks_[fx]==ranks_[fy]){parents_[fx]=fy;ranks_[fy]++;}else if(ranks_[fx]<ranks_[fy])parents_[fx]=fy;else parents_[fy]=fx;}int numIslands(vector<vector<char>>& grid) {if(grid.size()==0 ) return 0;int m=grid.size();int n=grid[0].size();if(n==1 && m==1) {if(grid[0][0]=='1') return 1;else return 0;}for(int i=0;i<m*n;i++){parents_.push_back(i);ranks_.push_back(0);}for(int i=0;i<m;i++)for(int j=0;j<n;j++){if(grid[i][j]=='0') continue;int cur_pos=i*n+j;//坐標(biāo)轉(zhuǎn)換//上邊if(i>0&&grid[i-1][j]=='1') Union(cur_pos-n,cur_pos);//左邊if(j>0&&grid[i][j-1]=='1')Union(cur_pos,cur_pos-1);}int count=0;for(int i=0;i<m;i++)for(int j=0;j<n;j++){int cur_pos=i*n+j;if(cur_pos==find(cur_pos)&&grid[i][j]=='1')count++;}return count;} };

    來源:力扣(LeetCode)
    鏈接:島嶼數(shù)量https://leetcode-cn.com/problems/number-of-islands
    著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有。商業(yè)轉(zhuǎn)載請聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

    ??途W(wǎng)-找朋友

    找朋友并查集裸題

    總結(jié)

    以上是生活随笔為你收集整理的并查集简单使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。