Union-Find算法学习笔记

这个课程把Union-Find作为第一讲,也借助这个问题来阐述如何科学、合理的构建一个好的算法。

构建算法的主要步骤如下:

  • 为问题建模
  • 构建一个解决问题的算法
  • 算法够快吗?存储空间是否合适?
  • 如果不够快或需要很大的存储空间,寻找原因
  • 尝试解决速度与存储空间问题
  • 不断尝试优化直到符合要求


动态连接问题(dynamic connectivity)

有N个独立的对象,每两个对象之间有两种状态,即连接状态与非连接状态,可以对这些对象进行两个操作,一个是Union,就是把两个对象连接起来,Find,查询两个对象是否处于连接状态。


在实际问题中对象有哪些呢?

  • 照片中的像素点
  • 网络中的每台计算机
  • 社交网络中的每个人
  • 计算机芯片中的每个晶体管
  • 数学集合中的每个元素
  • 程序中的每个变量
  • 一个整体系统中的金属部件

定义连接(Connection):

  • 反身性(每个对象与自身是连接的)
  • 对称性(p与q是连接的,则q与p也是连接的)
  • 传递性(p与q是连接的,q与r是连接的,则p与r也是连接的)

定义连接集合(Connected Components):

连接起来的对象组成的最大的集合。

例如下面的8个对象组成3个连接集合



两个操作:

Find

     查询两个对象是否在一个集合里。

Union

     如果两个对象不在一个集合里,合并两个集合


数据类型及API

目标:为算法设计高效的数据结构

  • 对象的数目N可能很大
  • 操作次数M可能很大
  • 查询与连接可能有交叉(例如进行连接前先进行查询操作)


你可能会想,so easy,记录每一个对象所属的连接集合,查询时直接对比,不就行了么?对,这就是Quick-find 算法,为每个对象设立一个id,记录它所属的连接集合

Find  Query,如果两个对象的id是相同的,那么它们就是处于连接状态的。

Union command  连接p,q时, 将所有与p有相同id的对象的id,全部更改为q的id。



例如,把对象1连接到对象8上,就需要查询所有的对象的id,把id为1的全部改为8

可以把这种结构看作一棵深度只有一层的扁平的树,在进行连接时,把所有的子树都移到了根节点上,但它的缺点是太慢了。每次都需要遍历所有的对象来寻找与p有相同id的对象并更改它们的id。

那么你可能会想了,在进行Union时,直接把1连接到8上就可以了,查询时,只需要查询两个对象是不是有相同的根节点不就就可以了嘛。这就是Quick-union算法,把所有对象按照树结构来进行存储,依然为每个对象设立一个id,id[i]是对象i的父节点

Find  Query  如果两个对象的根节点是相同的,那么它们就是处于连接状态的。

Union command  如果连接p,q, 那么将p的id改为q的id,即id[p]= id[q]。


但这样又带来一个新的问题,就是树可能长的很高,当树很高的时候,查询一个对象的根节点就很耗时。

那么能不能想个办法让树不要长高呢?看下面这个图,如果两个树合并的话,大树作为小树的子树,样子难看,效果肯定也很差嘛,那就加个判断吧,多用一个数组存储每个树所包含的对象数目,在进行树的合并的时候,把小的树(对象少的)作为大的树(对象多的)的子树,这就是Weighted Quick-Union算法。



从上图可以看到,Weighted Quick-Union 得到的树就扁平的多。


Weighted Quick-Union中,任意一个节点的深度<=lgN。

思考一下什么时候一个节点的深度会增加呢?当它处于较小的树的时候,

因为 N1<=N2,

所以 lg(N1+N2) >= lg(N1+N1) = 1+lg(N1) >= 1+depth(x) = new_depth(x)


说白了,就是Weighted Quick-Union 就是在Quick-Union的基础上压缩了路径(树高)嘛!能不能进一步再压缩一下呢?

课上介绍了两种方式,

一是在查询时,增加一个循环,将每一个查询路径上的节点都直接连接到根上。

另一个是将每个查询路径上的节点直接连接到它的祖父节点上。


最终各个算法效率的比较见下图。

理论上,WQUPC不是线性的,但从实际使用中来看,可以认为是线性的。

               


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值