图论算法----并查集中的启发式合并

一、启发式合并的算法原理

一听这名字,感觉好高大上,实际上很简单。

由于路径压缩在有些题目会损失海量的信息,用暴力并查集又要超时,所以就出现了启发式合并算法。

之前讲过并查集的大部分时间都浪费在了find()函数上,于是就对find()函数进行了优化,其实启发式合并算法可以使find()函数的时间复杂度控制在O(logn)左右。

并查集是一种树型的数据结构,而树也有它的深度,如果我们把一棵深度大的树的根节点接在了一棵深度小的树上,那么整棵树的深度为那一棵深度大的树的深度+1,如果我们把一棵深度小的树的根节点接在了一棵深度大的树上,则整棵树的深度为max(深度小的树的深度+1,深度大的树的深度)。这就是启发式合并的原理。

如果感觉很难理解,看下面的图就知道了。

1、有两棵树,一棵高度为3,一棵高度为5。

2、如果是普通的合并,就会造成高度为6的树。

3、如果是启发式合并,最后的树的的高度为5。

好了,启发式合并的原理讲得差不多了,可以发代码了,记住height[]数组初始化为1。

二、启发式合并的代码

void qfsunion(int x,int y)
{
    int a=find(x);
    int b=find(y);
    if(height[a]>height[b])
        fa[b]=a;
    else if(height[a]<height[b])
        fa[a]=b;
    else{
        fa[a]=b;
        height[b]++;
    }
}

配套一个find()函数:

int find(x)
{
     while(fa[x]!=0)
         x=fa[x];
      return x;
}

三、启发式合并与路径压缩之间的问题

这时有人会问了:为什么find()函数不用路径压缩呢?

原因很简单,因为有了路径压缩,启发式合并算法就没有保护数据的效果了。

可以看出,启发式合并+路径压缩并不是最好的选择,而且路径压缩在主动改变树的高度,但是height数组的值不能同步改变,有可能会让启发式合并出错。

四、一些补充

由于一些历史原因,本文所讲的启发式合并,现在在严格意义上称为按秩合并,而现在并查集的启发式合并算法是根据两棵树的节点数目进行合并,具体内容详见OI Wiki

并查集 - OI Wiki (oi-wiki.org)

### 并查集的时间复杂度与Ackermann函数关系 并查集(Union-Find)的数据结构,在引入启发式合并和路径压缩两种优化技术后,其找操作的均摊时间复杂度达到了近乎常数级别。具体来说,对于执行 \( m \) 次找操作的整体复杂度为 \( O(mα(m)) \),这里的 \( α(m) \) 表示的是阿克曼(Ackermann) 函数的一个反函数[^1]。 #### 阿克曼函数及其反函数的作用 阿克曼函数是一个增长速度极快的双参数函数,而它的反函数则增长得极其缓慢。实际上,在实际应用场景中遇到的情况里,\( α(n) \) 的值几乎不会超过 4 或者 5【此处应理解为理论上的极限情况】。因此,当提到并查集的操作复杂度时所说的 \( O(α(n)) \)[^3],意味着即使面对非常庞大的输入规模,该数据结构依然能够保持高效的性能表现。 #### 均摊复杂度解释 值得注意的是,并查集所声称的时间复杂度 \( O(α(n)) \) 实际上指的是**均摊复杂度**而非最坏情况下每次单独调用的确切开销。这意味着虽然个别询可能花费更多资源,但从长远来看——即考虑一系列连续操作后的总体效果——平均下来每一步所需的工作量是非常少的[^2]。 ```python def find(parent, i): if parent[i] != i: # 路径压缩 parent[i] = find(parent, parent[i]) return parent[i] def union(rank, parent, x, y): rootX = find(parent, x) rootY = find(parent, y) if rank[rootX] < rank[rootY]: parent[rootX] = rootY elif rank[rootX] > rankY: parent[rootY] = rootX else: parent[rootY] = rootX rank[rootX] += 1 ``` 这段Python代码展示了如何实现带路径压缩和按秩合并策略的`find` 和 `union` 方法来构建高效能的并查集实例。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值