发展一个有效算法的具体(一般)过程:

union-find用来解决dynamic connectivity,下面主要讲quick find和quick union及其应用和改进。

基本操作:find/connected queries和union commands

动态连接性问题的场景:

1.1  建立模型(Model the problem):

关于object:0-N-1

关于连接的等价性:

关于连接块:

关于基本操作find query和union command:

比如union操作:

目标:

练习:

答案:C。最后剩下的连接块有{0,5,6}{3,4}{1,2,7,8,9}。

1.2  算法及其改进(Algorithm and improvement):

1.2.1  Quick Find

实现过程:

  1. public class QuickFindUF
  2. {
  3. private int[] id;
  4.  
  5. public QuickFindUF(int N)
  6. {
  7. id = new int[N];
  8. for (int i = 0; i < N; i++)
  9. id[i] = i;
  10. }
  11.  
  12. public boolean connected(int p, int q)
  13. { return id[p] == id[q]; }
  14.  
  15. public void union(int p, int q)
  16. {
  17. int pid = id[p];
  18. int qid = id[q];
  19. for (int i = 0; i < id.length; i++)
  20. //这里有个约定:
  21. //p和q联合的时候,所有和p是一个连接块(connected conponents)的点的id都要设置为与id[q]相等
  22. if (id[i] == pid) id[i] = qid;
  23. }
  24. }

各个函数的时间复杂度:

弊端:

对N个实体做N次的union操作,时间复杂度是O(N2)。换言之,Quick find太慢,不适合大量的数据。

练习:

答案:C。最差情况就是除了id[q],其他元素都要改变。

1.2.2  Quick Union

说明:

实现过程:

  1. public class QuickUnionUF
  2. {
  3. private int[] id;//id[i],节点i的父节点
  4.  
  5. public QuickFindUF(int N)
  6. {
  7. id = new int[N];
  8. //划分为N棵子树,每个子树的根节点就是本身
  9. for (int i = 0; i < N; i++)
  10. id[i] = i;
  11. }
  12.  
  13. private int root(int i)//找打i所在子树的根节点
  14. {
  15. //如果id[i] == i,说明i是某一棵子树的根节点
  16. while (i != id[i]) i = id[i];
  17. return i;
  18. }
  19.  
  20. public boolean connected(int p, int q)
  21. {
  22. return root(p) == root(q);
  23. }
  24.  
  25. public void union(int p, int q)//将p所在子树的根节点的父节点设为q所在子树的根节点
  26. {
  27. int i = root(p);
  28. int j = root(q);
  29. id[i] = j;
  30. }
  31. }

各个操作的时间复杂度:注意quick union的union和find是最差情况(例如,形成的子树很高)的时间复杂度。

弊端:

练习:

答案:D。3的根节点是6:3->5->2->6。7的根节点是6:7->1->9->5->2->6。

练习:

答案:C

1.2.3  Weighted quick union

Improvement 1:weighting。为每个树保留track记录树的规模;union的时候将规模小的树的根节点添加为规模大的树的根节点的子节点。主要针对Quick union中容易出现树很高的情况。

实现过程:

  1. public class WeightedQuickUnionUF {
  2. private int[] id,sz;
  3.  
  4. public WeightedQuickUnionUF(int N)
  5. {
  6. id = new int[N];
  7. sz = new int[N];//记录以i为根节点的树的节点个数
  8. for (int i = 0; i < N; i++)
  9. {
  10. sz[i] = 1;
  11. id[i] = i;
  12. }
  13. }
  14.  
  15. private int root(int i)//和quick union相同
  16. {
  17. while (i != id[i]) i = id[i];
  18. return i;
  19. }
  20.  
  21. public boolean connected(int p, int q)//和quick union相同
  22. {
  23. return root(p) == root(q);
  24. }
  25.  
  26. public void union(int p, int q)
  27. {
  28. int i = root(p);
  29. int j = root(q);
  30. if (i == j) return;
  31. if (sz[i] < sz[j]){id[i] = j; sz[j] += sz[i];}
  32. else {id[j] = i; sz[i] += sz[j];}
  33. }
  34. }

各个函数的时间复杂度:注意到weighted quick union中的union和connected操作的时间复杂度都是log2N。

命题:按照Weighted quick union实现的树的任意一个节点的深度不会超过log2N。

证明:关注任意节点x。

1. 只有当包含x的子树T1作为lower tree被合并的时候,x的深度才有可能增加1。

2. 另一棵树T2,其中sz[T2]>=sz[T1]。

每合并1次,树的规模*2,并且最后的树的规模==N,所以x最多只能增加log2N次,意味着节点x最后的深度不会超过log2N。

Weighted quick union和Quick union的比较实例:

Weighted quick union实现结果更加均衡,叶节点到根的距离最大为4,每个节点到根节点的距离的平均要远远小于Quick union的结果。

1.2.4 Weighted quick union with path compressioin

Improvement 2:path compression。就是路径压缩。

实现过程有2种方式:主要区别是root函数的实现。

1. 找到当前点x的根节点后,将x与根节点相连路径上的所有节点的父节点设为根节点。

2. 在寻找当前点x的根节点的过程中,直接将x的父节点设置为x的父节点的父节点。

下面只展示union函数的实现:

方式1:

  1. private int root(int i)
  2. {
  3. if (id[i] == i) return i;//只有指向根节点才返回
  4. return id[i] = root(id[i]);
  5. }

方式2:

  1. private int root(int i)
  2. {
  3. while (i != id[i])
  4. {
  5. id[i] = id[id[i]];//指向父节点的父节点
  6. i = id[i];
  7. }
  8. return i;
  9. }

对N个点使用Weighted quick union with path compressioin中的union find操作m次的时间复杂度:

关于lg*的解释:http://stackoverflow.com/questions/2387656/what-is-olog-n/2387669

log* (n)- "log Star n" as known as "Iterated logarithm"

In simple word you can assume log* (n)= log(log(log(.....(log* (n))))

已经证明,union find问题的时间复杂度不可能到O(N)。

练习:

答案:

总结:

Algorithm partI 第2节课 Union−Find的更多相关文章

  1. centos DNS服务搭建 DNS原理 使用bind搭建DNS服务器 配置DNS转发 配置主从 安装dig工具 DHCP dhclient 各种域名解析记录 mydns DNS动态更新 第三十节课

    centos  DNS服务搭建  DNS原理  使用bind搭建DNS服务器 配置DNS转发 配置主从  安装dig工具  DHCP  dhclient  各种域名解析记录  mydns DNS动态更 ...

  2. 风炫安全Web安全学习第十六节课 高权限sql注入getshell

    风炫安全Web安全学习第十六节课 高权限sql注入getshell sql高权限getshell 前提条件: 需要知道目标网站绝对路径 目录具有写的权限 需要当前数据库用户开启了secure_file ...

  3. centos linux安全和调优 第四十一节课

    centos  linux安全和调优    第四十一节课 上半节课 Linux安全 下半节课 Linux调优 2015-07-01linux安全和调优 [复制链接]--http://www.apele ...

  4. centos shell编程6一些工作中实践脚本 nagios监控脚本 自定义zabbix脚本 mysql备份脚本 zabbix错误日志 直接送给bc做计算 gzip innobackupex/Xtrabackup 第四十节课

    centos   shell编程6一些工作中实践脚本   nagios监控脚本 自定义zabbix脚本 mysql备份脚本 zabbix错误日志  直接送给bc做计算  gzip  innobacku ...

  5. [iOS]Objective-C 第一节课

    Objective-C 第一节课 本节课的主要内容 创建Objective-C的第一个工程 HelloWorld Objective-C中的字符串 创建Objective-C的第一个工程 打开Xcod ...

  6. 《从零玩转python+人工智能-3》120,122节课深度优先疑问解答

     深度优先(从左往右): 按照这个原则来:至于使用栈,或者队列:根据它们不同的特性:最终务必保证最终结果是原继承结构的“从左往右”:所以,如果是栈,就是右侧先入栈,左侧再入(这样左侧能先出来,遵循从左 ...

  7. [转][南京米联ZYNQ深入浅出]第二季更新完毕课程共计16节课

    [南京米联]ZYNQ第二季更新完毕课程共计16节课 [第二季ZYNQ]                                                                  ...

  8. SpringBoot常用Starter介绍和整合模板引擎Freemaker、thymeleaf 4节课

    1.SpringBoot Starter讲解 简介:介绍什么是SpringBoot Starter和主要作用 1.官网地址:https://docs.spring.io/spring-boot/doc ...

  9. centos mysql 实战 第一节课 安全加固 mysql安装

    centos mysql  实战  第一节课   安全加固  mysql安装 percona名字的由来=consultation 顾问+performance 性能=per  con  a mysql ...

随机推荐

  1. excel中如何让每n行显示同一个数据

    由于需要将数据按照下表格式存储,以方便读取展示,年份列需要每隔7行再递增1 方法: 1. 输入这个公式: = INT((ROW(E1)-1)/ 5)+ 1 进入一个空白单元格,您可以在其中填写序列号, ...

  2. 解决“找不到请求的 .Net Framework Data Provider。可能没有安装.”错误

    问题: 这几天在装.NET 的开发环境,在装好VS2013和Oracle 11g之后,做了一个测试项目,运行调试没问题 但是涉及到数据库相关操作,如新建数据集.连接数据库等在调试的时候则会出现如下错误 ...

  3. django drf JWT

    建议使用djangorestframework-jwt或者djangorestframework_simplejwt,文档为 https://github.com/GetBlimp/django-re ...

  4. Android 中 LayoutParams 的用法

    一个控件应当使用它的父控件的 LayoutParams 类型.因此,一个 TableVow 应该使用 TableLayout.Params . 所以,以一个 TableRow 为例: TableRow ...

  5. C语言—第二次作业

    1.本章学习内容 1.1思维导图 1.2本章学习体会即代码量学习体会 1.2.1学习体会 在本章中对循环的内容进行了加深训练,学习了一种解决问题的方法循环嵌套,也学到了伪代码的运用,在描述算法是运用伪 ...

  6. 【Oracle 12c】CUUG OCP认证071考试原题解析(30)

    30.choose the best answer Examine the commands used to create DEPARTMENT_DETAILS and COURSE_DETAILS: ...

  7. P5282 【模板】快速阶乘算法(多项式运算+拉格朗日插值+倍增)

    题面 传送门 前置芝士 优化后的\(MTT\)(四次\(FFT\)) 题解 这里有多点求值的做法然而被\(shadowice\)巨巨吊起来打了一顿,所以来学一下倍增 成功同时拿到本题最优解和最劣解-- ...

  8. [转] Cisco路由器DNS配置

    禁用Web服务 Cisco路由器还在缺省情况下启用了Web服务,它是一个安全风险.如果你不打算使用它,最好将它关闭.举例如下: Router(config)# no ip http server 配置 ...

  9. Vim 中的持久撤消

    Vim中的持久撤消 阅读文本大约需要俩分钟. 在 Vim 中像其他文本编辑器一样,你可以在当前会话中执行 "撤销/重做" .当一旦会话关闭,则你需要重新打开一个新文章,运行撤销将不 ...

  10. Markdown入门简介

    参考 http://sspai.com/25137 作者: Te_Lee 文章来源: 少数派 Markdown入门简介(使用工具Haroopad) 一.使用的工具----haroopad(http:/ ...