算法4(Algorithms4)- Part 1 动态连通性(Dynamic Connectivity)1

本系列文章记录学习的过程。

0. 前言

由于课程授课和课件(Lecture Slides)均为英文,所以文中许多专有名词会标注英文,中文翻译参考《Algorithms Fourth Edition》中文版。课件以及其它资料下载链接会在文末给出。

1. 动态连通性(Dynamic Connectivity)

1.1 定义

什么是动态连通性?

Given a set of N objects.
・Union command: connect two objects.
・Find/connected query: is there a path connecting the two objects?

给定几个数的集合

  • Union操作: 在两个数之间加一条连接。
  • Find/connected查询: 判断两个数之间是否有连接。
Union-Find
Union-Find

1.2 建立模型

如何选择具体的数据结构模型呢?
动态连通性的应用十分广泛:

  • 照片的像素
  • 网络中的电脑
  • 社交网络中的两个人
  • 电路芯片中的晶体管
  • 数学集合中的元素
    ...

比较容易实现的选择:使用数组,让数组的每个下标代表每个数

我们继续假设: “相连(is connected to)” 是两个数之间的一种关系,且这种关系满足以下条件:

  • 自反性(Reflexive): p和p是相连的;
  • 对称性(Symmetric): 如果p和q是相连的,那么q和p也是相连的;
  • 传递性(Transitive): 如果p和q相连且q和r相连,那么p和r相连。

当两个数相连时,它们属于同一个等价类(Connected Components)。
等价类,就是所有相连的数的集合,这个集合必须包含所有相连的数。

ConnectedComponents
ConnectedComponents

具体的操作,给定两个数:

  • Find操作: 查看两个数是否属于同一个等价类。
  • Union操作: 将两个数连接起来,这个操作其实就是将两个数所在的等价类联合成一个等价类。
UnionFindOperation
UnionFindOperation

在这里约定一下使用的术语:

英文 汉语术语
Connected Components 等价类 / 分量
node 节点

1.3 Union-Find数据类型(Union-Find data type)

由1.2 我们得出了简单的数据模型,现在需要设计具体的数据类型,我们的目标是:

  • 为Union-Find操作设计出一个高效的数据类型
  • 每个数据类型包含N个数,N可能会很大
  • 操作的次数M可能很大
  • Find操作和Union操作可能会交叉进行

以下是API:

public class UF
UF(int N) 用整数N(0到N-1)初始化N个点
void union(int p, int q) 为点p和点q之间添加一条连接
boolean connected(int p, int q) 判断点p和点q是否属于同一个分量
int find(int p) p所在分量的标识符(0到N-1)
int count() 分量的数量

2. Quick Find算法

2.1 数据结构

  • 整数型数组id[],长度为N。
  • p和q是相连的等价于数组中p下标和q下标的数相同。
QuickFind
QuickFind

2.2 Java实现

QFJava
QFJava

2.3 算法分析

QuickFind算法太慢了。
下表是最坏情况下QuickFind算法对一组点操作使用的时间消耗。

算法 初始化 union操作 find操作
QuickFind N N 1

Union操作过于缓慢:如果要对N对点进行union操作,最多需要对数组访问N^2次。

3. Quick Union算法

3.1 数据结构

  • 整数型数组id[],长度为N。
  • id[i]中存储i的父节点( 也就是形成一个链接,直到其父节点就是它自己,说明到头了)
  • i的根节点(root)是id[id[id[id[...id[i]...]]]]

具体操作:

  • Find操作:检查p和q是否拥有同一个根节点 。
  • Union操作: 为了合并p和q各自所在的分量,将p的根节点改为q的根节点。


    QuickUnion
    QuickUnion

3.2 Java实现

QuickUnionJava
QuickUnionJava

3.3 算法分析

对一对点进行操作需要访问数组的次数,图中是最坏情况。

算法 初始化 union操作 find操作
QuickFind N N 1
QuickUnion N N* N

*:包括了寻找根节点的操作。

QuickFind的缺点

  • Union操作太慢了,最差为N
  • 树是平的,但是维护这个状态时间耗费太大了

QuickUnion的缺点

  • 树可能会很高
  • Find操作太慢了,最差为N

4. 改进1 - 加权(weighting)

4.1 数据结构

加权QuickUnion(Weighted QuickUnion)

  • 改进QuickUnion,避免太高的树
  • 对每个树的大小(包含点的数量)进行记录
  • union操作时,比较两个点所在树的大小,小数的根节点连接到大树的根节点之上

数据结构其实和QuickUnion相同,但是需要再维护一个额外的数组sz[i],用来记录以i节点为根节点的分量的大小(及分量中数的多少)

4.2 Java实现

Find操作:和QuickUnion相同

        return root(p) == root(q);

Union操作:改进的QuickUnion

  • 将较小的树的根节点连接到大的树的根节点上
  • 不断更新sz[]数组
            int i = root(p);
            int j = root (q);
        
            if(i == j)  return;
            if(sz[i] < sz[j])   { id[i] = j;    sz[j] += sz[i];}
            else                { id[j] = i;    sz[i] += sz[j];}

4.3 算法分析

quickunion-weightedTrees
quickunion-weightedTrees

运行时间

  • Find操作: 时间和p以及q的深度成正比
  • Union操作: 给定根节点,时间为常数

命题: 任意节点x,其深度最大为lg N 。

证明:
什么时候x的深度会增大呢?

当树T2比树T1大,即|T2| >= |T1|时,包含x的树T1成为另一个树T2的子树时,x的深度会加1。由此推出:

  • T1和T2合起来的新树,其大小至少是之前T1的2倍。(也就是x所在的树大小增大1倍,x的深度加1)
  • 包含x的树最多可以翻倍lg N 次。


    WeightedQuickUnionAnalysis
    WeightedQuickUnionAnalysis

算法分析

算法 初始化 union操作 find操作
QuickFind N N 1
QuickUnion N N* N
weighted QU N (lg N)* lg N

*:包括了寻找根节点的操作。

还可以优化吗?答案是肯定的。

5. 改进2 - 路径压缩(Path Compression)

5.1 数据结构

在计算点p的根节点root之后,每个经过的节点,如果其根节点不为root的话,让其根节点变成root,如图是带路径压缩的QuickUnion算法(Quick Union with Path Compression),下图是具体的过程。

5.2 Java实现

            private int root(int i) {
                int temp;   // 临时节点
                
                while(i != id[i]) {
                    temp = id[i];   // 用临时节点记录i节点的父节点
                    id[i] = find(i);// 将i节点的父节点置为根节点
                    i = temp;       // 对i节点之前的父节点进行重复性判断
                }
                return i;
            }

5.3 算法分析

使用带路径压缩的加权Quick Union算法,对于N个数,M次操作时,访问数组次数最多为c (N + M lg* N)。
(c为常数, lg* N是lg(lg(lg(...lg()...)))。)

对于N个数,M次操作时,有没有线性访问数组次数的算法呢?

  • 理论上, WQUPC(Weighted Quick Union & Path Compression)不是线性的
  • 实际中,WQUPC基本是线性的

现已证明,没有完全的线性算法存在。

6. 总结

使用带路径压缩的加权Quick Union算法,使得之前不可能被解决的问题现在可以被解决。

对于109次union操作和109次find操作:

  • WQUPC让时间从30年变成了6s
  • 超级计算机并不能帮助太多,但是好的算法可以让问题得到充分解决

7. 参考网址

[1] 课程首页(Course Page)
[2] Algorithms 4th
[3] 课件下载(Lecture Slides)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容