python实现一个简单的并查集的示例代码


Posted in Python onMarch 19, 2018

并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。常常在使用中以森林来表示。

并查集有三种基本操作,获得根节点,判断两节点是否连通,以及将两不连通的节点相连(相当于将两节点各自的集合合并)

用UnionFind类来表示一个并查集,在构造函数中,初始化一个数组parent,parent[i]表示的含义为,索引为i的节点,它的直接父节点为parent[i]。初始化时各个节点都不相连,因此初始化parent[i]=i,让自己成为自己的父节点,从而实现各节点不互连。

def __init__(self, n):
    self.parent = list(range(n))

由于parent[i]仅表示自己的直接父节点,查询两个节点是否相交需要比较它们的根节点是否相同。因此要封装一个查询自己根节点的方法。

def get_root(self, i):
    while i != self.parent[i]:
      i = self.parent[i]

    return i

接下来可以通过来比较根节点是否相同来判断两节点是否连通。

def is_connected(self, i, j):
    return self.get_root(i) == self.get_root(j)

当要连通两个节点时,我们要将其中一个节点的根节点的parent,设置为另一个节点的根节点。注意,连通两个节点并非仅仅让两节点自身相连,实际上是让它们所属的集合实现合并。

def union(self, i, j):
    i_root = self.get_root(i)
    j_root = self.get_root(j)
    self.parent[i_root] = j_root

接下来我们做两个小优化。

由于调用get_root时需要通过不断找自己的直接父节点,来寻找根节点,如果这棵树的层级过深,会导致性能受到严重影响。因此我们需要在union时,尽可能的减小合并后的树的高度。

在构造函数中新建一个数组rank,rank[i]表示节点i所在的集合的树的高度。

因此,当合并树时,分别获得节点i和节点j的root i_root和j_root之后,我们通过访问rank[i_root]和rank[j_root]来比较两棵树的高度,将高度较小的那棵连到高度较高的那棵上。如果高度相等,则可以随便,并将rank值加一。

def union(self, i, j):
    i_root = self.get_root(i)
    j_root = self.get_root(j)

    if self.rank[i_root] == self.rank[j_root]:
      self.parent[i_root] = j_root
      self.rank[j_root] += 1
    elif self.rank[i_root] > self.rank[j_root]:
      self.parent[j_root] = i_root
    else:
      self.parent[i_root] = j_root

通过对union操作的改良可以防止树的高度过高。我们还可以对get_root操作本身进行优化。

当前每次执行get_root时,需要一层一层的找到自己的父节点,很费时。由于根节点没有父节点,并且文章开始处提到过如果一个节点没有父节点,那么它的父节点就是自己,因此可以说只有根节点的父节点是自己本身。现在我们加上一个判断,判断当前节点的父节点是否为根节点,如果不为根节点,就递归地将自己的父节点设置为根节点,最后返回自己的父节点。

def get_root(self, i):
    if self.parent[i] != self.parent[self.parent[i]]:
      self.parent[i] = self.get_root(self.parent[i])
    return self.parent[i]

以上是python实现一个简单的并查集的方式。希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python-基础-入门 简介
Aug 09 Python
python开发之thread实现布朗运动的方法
Nov 11 Python
Python实现简单文本字符串处理的方法
Jan 22 Python
Python错误处理操作示例
Jul 18 Python
PyCharm在新窗口打开项目的方法
Jan 17 Python
在Python中字典根据多项规则排序的方法
Jan 21 Python
Pandas删除数据的几种情况(小结)
Jun 21 Python
Python求均值,方差,标准差的实例
Jun 29 Python
基于spring boot 日志(logback)报错的解决方式
Feb 20 Python
Python requests设置代理的方法步骤
Feb 23 Python
在pycharm中使用matplotlib.pyplot 绘图时报错的解决
Jun 01 Python
Python如何操作docker redis过程解析
Aug 10 Python
python使用筛选法计算小于给定数字的所有素数
Mar 19 #Python
python将每个单词按空格分开并保存到文件中
Mar 19 #Python
python将文本分每两行一组并保存到文件
Mar 19 #Python
python: line=f.readlines()消除line中\n的方法
Mar 19 #Python
Python File readlines() 使用方法
Mar 19 #Python
Python cookbook(数据结构与算法)筛选及提取序列中元素的方法
Mar 19 #Python
django用户注册、登录、注销和用户扩展的示例
Mar 19 #Python
You might like
PHP开发框架总结收藏
2008/04/24 PHP
php5 pdo新改动加载注意事项
2008/09/11 PHP
linux下 C语言对 php 扩展
2008/12/14 PHP
PHP编程风格规范分享
2014/01/15 PHP
PHP生成数组再传给js的方法
2014/08/07 PHP
php实现文本数据导入SQL SERVER
2015/05/17 PHP
php 解决扫描二维码下载跳转问题
2017/01/13 PHP
laravel 实现登陆后返回登陆前的页面方法
2019/10/03 PHP
关于Jqzoom的使用心得 jquery放大镜效果插件
2010/04/12 Javascript
jQuery ajax dataType值为text json探索分享
2013/09/23 Javascript
基于jQuery实现动态搜索显示功能
2016/05/05 Javascript
基于JS实现密码框(password)中显示文字提示功能代码
2016/05/27 Javascript
基于js实现二级下拉联动
2016/12/17 Javascript
jQuery实现的checkbox级联选择下拉菜单效果示例
2016/12/26 Javascript
vue addRoutes实现动态权限路由菜单的示例
2018/05/15 Javascript
微信小程序实现日历功能
2018/11/27 Javascript
JS与SQL方式随机生成高强度密码示例
2018/12/29 Javascript
JS浅拷贝和深拷贝原理与实现方法分析
2019/02/28 Javascript
了解JavaScript中let语句
2019/05/30 Javascript
一次让你了解全部JavaScript的作用域
2019/06/24 Javascript
js实现计时器秒表功能
2019/12/16 Javascript
[01:05:59]Mineski vs Secret 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.22
2019/09/05 DOTA
Python入门篇之文件
2014/10/20 Python
Python中处理字符串的相关的len()方法的使用简介
2015/05/19 Python
python web框架学习笔记
2016/05/03 Python
PyQt5实现暗黑风格的计时器
2019/07/29 Python
tensorflow之tf.record实现存浮点数数组
2020/02/17 Python
Python爬虫HTPP请求方法有哪些
2020/06/03 Python
简单了解Django项目应用创建过程
2020/07/06 Python
工程师必须了解的LRU缓存淘汰算法以及python实现过程
2020/10/15 Python
canvas绘制视频封面的方法
2018/02/05 HTML / CSS
学习方法演讲稿
2014/05/10 职场文书
国富论读书笔记
2015/06/26 职场文书
美容院管理规章制度
2015/08/05 职场文书
读完《骆驼祥子》的观后感!
2019/07/05 职场文书
关于springboot 配置date字段返回时间戳的问题
2021/07/25 Java/Android