并查集数据结构
只有 find
和 union
操作, 它用于处理一些不交集的 合并 及 查询 问题。
find
: 确定元素所在的集合
union
: 合并两个不相交集合
并查集的数据结构
初始化
初始化时,每个节点都是一个集合。
union(x,y)
合并的过程是: 先找到x(y)
节点的祖先节点(find(x)) [xp,yp]
,然后比较祖先节点是否相同,若相同则完成合并。负责将其中的祖先节点 (xp
) 的父节点指向另一个祖先节点 (yp
):parent[xp] = yp;
一个简单的并查集模版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| int parent[MAXLEN];
void makeSet(int k){ for(int i =0;i<k;i++) parent[i] = i; }
int find(int x){ if(parent[x] != x){ parent[x] = find(parent[x]); } return parent[x]; }
void union(int x,int y){ int xp = find(x); int yp = find(y); if(xp != yp){ parent[xp] = yp; } while(parent[x]!=yp){ int t = parent[x]; parent[x]=yp; x = t; } }
|
路径压缩
这样的确可以达成目的,但是显然效率实在太低。为什么呢?因为我们使用了太多没用的信息,我的祖先是谁与我父亲是谁没什么关系,这样一层一层找太浪费时间,不如我直接当祖先的儿子,问一次就可以出结果了。甚至祖先是谁都无所谓,只要这个人可以代表我们家族就能得到想要的效果。把在路径上的每个节点都直接连接到根上,这就是路径压缩。
并查集的应用
1. 统计不相交集合的个数
200. 岛屿数量
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [ ["1","1","1","1","0"], ["1","1","0","1","0"], ["1","1","0","0","0"], ["0","0","0","0","0"] ] 输出:1
示例 2:
输入:grid = [ ["1","1","0","0","0"], ["1","1","0","0","0"], ["0","0","1","0","0"], ["0","0","0","1","1"] ] 输出:3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include<iostream> #include<vector> #include<string>
using namespace std;
class Solution { public: struct Node{ int x; int y; Node():x(0),y(0){}; Node(int x, int y):x(x),y(y){}; bool equal(Node node){return node.x == x && node.y == y;}; };
Node find(vector<vector<Node>> &parent, Node node){ while(!node.equal(parent[node.x][node.y])){ node = parent[node.x][node.y]; } return node; } bool isParent(vector<vector<Node>> &parent, Node node){ return node.equal(parent[node.x][node.y]); } void unionNode(vector<vector<Node>> &parent, Node x, Node y){ Node xp = find(parent,x); Node yp = find(parent,y); if(!xp.equal(yp)) { parent[xp.x][xp.y] = yp; } while(!x.equal(yp)){ Node node = parent[x.x][x.y]; parent[x.x][x.y] = yp; x = node; } } int numIslands(vector<vector<char>>& grid) { int m = grid.size(), n = grid[0].size(); vector<vector<Node>> parent(m,vector<Node>(n,Node())); for(int i =0;i<m;i++){ for(int j=0;j<n;j++){ parent[i][j] = Node(i,j); } } vector<int> xd = {-1,0,1,0}; vector<int> yd = {0,1,0,-1}; for(int i =0;i<m;i++){ for(int j=0;j<n;j++){ if(grid[i][j] == '0') continue; for(int k =0;k< 4;k++){ int x = xd[k] + i; int y = yd[k] + j; if(x >=0 && x < m && y >=0 && y < n){ if(grid[x][y] == '1') unionNode(parent,Node(i,j),Node(x,y)); } } } } int ans = 0; for(int i =0;i<m;i++){ for(int j = 0;j<n;j++){ if(grid[i][j] == '1' && isParent(parent,Node(i,j))) ans++; } } return ans; } };
|
Reference
https://oi-wiki.org/ds/dsu/
https://leetcode-cn.com/problems/number-of-provinces/solution/jie-zhe-ge-wen-ti-ke-pu-yi-xia-bing-cha-0unne/