并查集(Union Find)

Posted 文大侠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并查集(Union Find)相关的知识,希望对你有一定的参考价值。

算法背景

Union Find算法,中文并查集。主要用来解决图论中的连通判断问题,简单抽象问题为:

  1. 平面上有n个点
  2. 给定他们之间两两连接关系

要求输入任意两个点,判断他们是否能够有一条路径联通

算法步骤

一旦有连接,就把一个节点设为另一个节点的父节点,最终连通的点会构成一颗树。通过判断两个节点的根节点是否相同,即可判断是否连通。具体如下

  1. 初始化时,每个节点指向自己,也就是根节点
  2. 遍历给定的两两连接关系,分别找各自的根节点,将两个根节点连接起来
  3. 判断是否联通很简单,找两个点的根结点是否相同

整个过程是不断合并树的过程,为了保证更优的效率,两个优化点

  1. 合并树的过程尽量保证平衡,这里引入根节点权重,小树合并到大树上,也就是秩优化
  2. 查找过程尽量快,这里引入路径压缩,把查找过程中的节点全部直接挂到根结点上,相当于一个均摊的过程

参考 https://mp.weixin.qq.com/s/gUwLfi25TYamq8AJVIopfA

代码详解

type UF struct {
	parent []int
	sz     []int
}

// 初始化union find
func getUF(n int) *UF {
	parent := make([]int, n)
	sz := make([]int, n)

	for i := 0; i < n; i++ {
		parent[i] = i // 初始化父节点指向自己,即根节点指向自己
		sz[i] = i     // 树高初始化为1
	}

	return &UF{parent, sz}
}

// 关联
func (u *UF) union(i int, j int) {
	root_i := u.find(i)
	root_j := u.find(j)

	if root_i == root_j {
		return
	}

	// 小树挂到大树上,秩优化
	if u.sz[root_i] > u.sz[root_j] {
		u.parent[root_j] = root_i
	} else {
		u.parent[root_i] = root_j

		if u.sz[root_i] == u.sz[root_j] {
			u.sz[root_j] += 1
		}
	}
}

// 查找根节点
func (u *UF) find(i int) int {
	if u.parent[i] != i {
		u.parent[i] = u.find(u.parent[i]) // 递归,路径压缩
	}

	return u.parent[i]
}

// 判断是否连通
func (u *UF) connected(i int, j int) bool {
	root_i := u.find(i)
	root_j := u.find(j)

	return root_i == root_j
}

关联leetcode

leetcode关联题目参考 https://books.halfrost.com/leetcode/ChapterTwo/Union_Find/

  • 源代码位置 https://github.com/JimWen/go-algo/tree/main/unionfind

原创,转载请注明来自

  • 博客[https://blog.csdn.net/wenzhou1219](https://
    wenzhou1219)
  • 个人网站http://jimwen.net/

以上是关于并查集(Union Find)的主要内容,如果未能解决你的问题,请参考以下文章

并查集详解

Union-Find(并查集): Quick union improvements

并查集(Union Find)

并查集(Union-Find)

第三十一篇 玩转数据结构——并查集(Union Find)

Union-Find 并查集算法