最近写到一道并查集的题,发现自己记得还是不太清楚,写一篇加深记忆
并查集–合并与查询元素分组
并查集是一种用来管理元素分组情况的数据结构,并查集可以高效地进行一下两种操作:
- 查询两个元素是否在同一组
- 合并两个元素所在的组
不过并查集虽然可以进行合并操作,却无法进行分割操作,需要注意
结构:树形结构-每组对应一颗树
每个元素对应一个节点,每个组对应一棵树。在并査集中,哪个节点是哪个节点的父亲以及树的形状等信息无需多加关注,整体组成一个树形结构才是重要的。
初始化
最开始初始化时并没有边
合并-根连接根
像下图一样,从一个组的根向另一个组的根连边,这样两棵树就变成了一棵树,也就把两个组合并为一个组了。
查询
为了査询两个节点是否属于同一组,我们需要沿着树向上走,来査询包含这个元素的树的根是谁。如果两个节点走到了同一个根,那么就可以知道它们属于同一组。在下图中,元素2和元素5都走到了元素1,因此它们属于同一组。另一方面,由于元素7走到的是元素6, 因此同元素2或元素5属于不同组。
注意事项
作为一棵树,如果发生了退化,复杂度就会大大提高,因此在并查集的维护过程中,我们必须防止退化的发生
Tips:如何避免树退化为链
(1)记录每棵树的高度,合并时小的向大的进行连接。
(2)路径压缩,在查询过程中所有经过的节点全部都直接连接到根节点上。
路径压缩往往是最常用的方法,对于每个节点,一旦向上走到了一次根节点,就把这个点到父亲的边改为直接连向根。在此之上,不仅仅是所查询的节点,在查询过程中向上经过的所有的节点,都改为直接连到根上。这样再次查询这些节点时,就可以很快知道根是谁了。
复杂度分析
对 n n n个元素进行一次操作的复杂度是 O ( α ( n ) ) O(\alpha(n)) O(α(n)), α ( n ) \alpha(n) α(n)是阿克曼函数的反函数,是一个比 log ( n ) \log(n) log(n)操作还要快的过程,注意—这是均摊复杂度。