Kruskal’s MST Algorithm
- 另一个用于解决MST的贪心算法
- 以下讨论仍然保留之前的假设(全联通、所有的边代价都是不同的)
- 割性质:既有割的最小代价交边一定在MST中
- 算法
- 将所有的边按照代价升序排列
- 初始化: T = ∅ T = \emptyset T=∅
- 迭代:1到
m
m
m(遍历每一条边)
- 如果 T ∪ { i } T \cup \{i\} T∪{i} 没有环,将 i i i加入到 T T T中
- T T T即为最终结果
- 直接实现
- 搜索: O ( m log n ) O(m \log n) O(mlogn)——因为边的数量最多为点的平方
- 迭代: O ( m ) O(m) O(m)次迭代, O ( n ) O(n) O(n)次检查是否存在环(BFS)
- 总时间复杂度: O ( m n ) O(mn) O(mn)
- 并查集实现
- 可以实现在常数时间内检查是否有环存在—— O ( m log n ) O(m \log n) O(mlogn)
- 并查集:维护一组实例的划分
find(x)
:返回输入所在组的名字union(i, j)
:将两个组合并到一起
- 对Kruskal算法
- 添加一条边,要连结两个不同的组
- 并查集
- 每一个联通分量维护一个链式结构
- 每一个连通分量可以将任一个节点作为leader
- 不变量:每个连通分量内的顶点指向其leader
- 常数时间检查一条边上的两个点是否在同一个联通分量——是否具有相同的leader
- 不变量维护
- 当一条边 ( u , v ) (u,v) (u,v)加入 T T T,两个端点所在分量将会合并
- 保留较大分量的标签,将其领导者信息连接到较小的分量的节点上
- 增加一个分量大小计算量,尽在合并时更新,易于维护
- Kruskal算法:查询环只需要常数时间 O ( 1 ) O(1) O(1),并查集更新 O ( n log n ) O(n \log n) O(nlogn)—— O ( m log n ) O(m \log n) O(mlogn)
Clustering
- 聚类:给定 n n n个点,将其归类为合理的若干组
- 假设
- 给定一个相似度度量标准 d ( p , q ) d(p, q) d(p,q)
- 指标满足对称性 d ( p , q ) = d ( q , p ) d(p, q) = d(q, p) d(p,q)=d(q,p)
- 目标:同一聚簇内的点具有“靠近”的性质
- 最大区分K聚类
- 假设聚簇个数 k k k已知
- 区分距离:两个聚簇内最近点对距离
- 目标:给定距离度量和聚簇个数,形成的聚簇具有最大区分距离
- 算法:初始化每个点作为一个聚簇,每次选择所有聚簇的区分距离最小的,合并之,直到只剩 k k k个聚簇
- 其实思路接近Kruskal,但是更早地结束(MST实际是一个聚簇)
Advanced Union Find
- 查找过程,每个节点直接指向其组内领导者
- O ( 1 ) O(1) O(1)的查找时间
- O ( n log n ) O(n \log n) O(nlogn)的合并时间
- Lazy Unions
- 初始化:每个节点各自为政
- 查找:从查询节点遍历父节点,直到根节点(自己指向自己)
- 合并:首先找到欲合并点的根节点,更新其中一个根节点的指针,指向另外一个根节点
- 旧领导者连接到新领导者
- Pro:合并操作简化到2次
find
和1次union
(修改一个连接, O ( 1 ) O(1) O(1)) - Con:由于不是所有节点都指向其领导者,因此需要遍历一个路径以寻找领导者——时间复杂度不能保证 O ( 1 ) O(1) O(1)
- Union by Rank
- 对Lazy Union,不对合并过程限制的话,可能产生一颗非常高的树
- 最糟糕情形下,查找和合并的时间复杂度都能达到 O ( n ) O(n) O(n)
- 我们需要树尽可能地浅
- 排序量
rank[x]
:对x
所在子树,其中节点查询到达x
本身的最大跳转次数- 初始化,所有的节点的排序值为0
- 实际上就是树的深度
- Union By Rank:选择根节点排序量较大的作为合并后的根节点
- 如果两个根节点的排序量相等,合并后的根节点排序量+1
- 否则,排序量不做修改
- 最大的排序量不会超过 log 2 ( n ) \log_2 (n) log2(n)
- 不变量
rank[x]
只会随时间增长- 只有根节点的
rank[x]
才会增长 - 某一结点到根节点,
rank[x]
严格增长
- 引理:对于任意的并查集操作,最多有 n 2 r \frac {n} {2^r} 2rn个节点的排序量为 r r r
- 结论:最大排序量必然不超过 log 2 n \log_2 n log2n
- 结论:使用union by rank 的并查集,查找时间复杂度不会超过 O ( log n ) O(\log n) O(logn)
- 对Lazy Union,不对合并过程限制的话,可能产生一颗非常高的树
- Path Compression
- 在完成
find(x)
操作之后,建立一条直接到达根节点的捷径 - Pro:加速查找速度
- Con:增加一个常数时间开销(回标)
- 和Rank搭配:所有的排序量按照不使用路径压缩的情形处理
- 至此,排序量已经失去了之前的定义表述,只是最大跳转次数的上界
- 但是,由于处理流程不变,只是树变得更“扁”了,所以引理仍然成立
- 同时,父节点的排序量会严格大于当前节点
- Hopcroft-Ulman理论:union by rank + path compression,会让时间复杂度达到 O ( m log ∗ n ) O(m \log^\ast n) O(mlog∗n),其中 log ∗ n \log^\ast n log∗n表示对 n n n不断取2对数, 直到结果不大于1前的取对数次数
- 在完成