2022.3.24 图论——并查集(UNION-FIND)算法


一、并查集(UNION-FIND)算法

参考文章

1.定义

并查集被很多OIer认为是最简洁而优雅的数据结构之一,主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作:

合并(Union):把两个不相交的集合合并为一个集合。
查询(Find):查询两个元素是否在同一个集合中。

现在我们的 Union-Find 算法主要需要实现这两个 API:

class UF {
   
    /* 将 p 和 q 连接 */
    public void union(int p, int q);
    /* 判断 p 和 q 是否连通 */
    public boolean connected(int p, int q);
    /* 返回图中有多少个连通分量 */
    public int count();
}

2.连通的概念

「连通」是一种等价关系,也就是说具有如下三个性质:

1、自反性:节点 p 和 p 是连通的。
2、对称性:如果节点 p 和 q 连通,那么 q 和 p 也连通。
3、传递性:如果节点 p 和 q 连通,q 和 r 连通,那么 p 和 r 也连通。

例:
在这里插入图片描述
0~9 任意两个不同的点都不连通,调用 connected 都会返回 false,连通分量为 10 个。
如果现在调用 union(0, 1),那么 0 和 1 被连通,连通分量降为 9 个。
再调用 union(1, 2),这时 0,1,2 都被连通,调用 connected(0, 2) 也会返回 true,连通分量变为 8 个。

3.基本思路

我们使用森林(若干棵树)来表示图的动态连通性,用数组来具体实现这个森林。设定树的每个节点有一个指针指向其父节点,如果是根节点的话,这个指针指向自己。比如说刚才那幅 10 个节点的图,一开始的时候没有相互连通,就是这样:
在这里插入图片描述
如果某两个节点被连通,则让其中的(任意)一个节点的根节点接到另一个节点的根节点上:
在这里插入图片描述

class UF {
   
    // 记录连通分量
    private int count;
    // 节点 x 的节点是 parent[x]
    private int[] parent;

    /* 构造函数,n 为图的节点总数 */
    public UF(int n) {
   
        // 一开始互不连通
        this.count = n;
        // 父节点指针初始指向自己
        parent = new int[n];
        for (int i = 0; i < n; i++)
            parent[i] = i;
    }
	
	public boolean connected(int p, int q) {
   
    	int rootP = find(p);
    	int rootQ = find(q);
    	return rootP == rootQ;
	}

    public void union(int p, int q) {
   
    	int rootP = find(p);
    	int rootQ = find(q);
    	if (rootP == rootQ)
        	return;
    	// 将两棵树合并为一棵
    	parent[rootP] = rootQ;
    	// parent[rootQ] = rootP 也一样
    	count--; // 两个分量合二为一
	}
	
	/* 返回某个节点 x 的根节点 */
	private int find(int x) {
   
    	// 根节点的 parent[x] == x
    	while (parent[x] != x)
       	 	x = parent[x];
    	return x;
	}

	/* 返回当前的连通分量个数 */
	public int count() {
   
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值