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

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

实现过程:

 public class QuickFindUF
{
private int[] id; public QuickFindUF(int N)
{
id = new int[N];
for (int i = 0; i < N; i++)
id[i] = i;
} public boolean connected(int p, int q)
{ return id[p] == id[q]; } public void union(int p, int q)
{
int pid = id[p];
int qid = id[q];
for (int i = 0; i < id.length; i++)
//这里有个约定:
//p和q联合的时候,所有和p是一个连接块(connected conponents)的点的id都要设置为与id[q]相等
if (id[i] == pid) id[i] = qid;
}
}

各个函数的时间复杂度:

弊端:

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

练习:

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

1.2.2  Quick Union

说明:

实现过程:

 public class QuickUnionUF
{
private int[] id;//id[i],节点i的父节点 public QuickFindUF(int N)
{
id = new int[N];
//划分为N棵子树,每个子树的根节点就是本身
for (int i = 0; i < N; i++)
id[i] = i;
} private int root(int i)//找打i所在子树的根节点
{
//如果id[i] == i,说明i是某一棵子树的根节点
while (i != id[i]) i = id[i];
return i;
} public boolean connected(int p, int q)
{
return root(p) == root(q);
} public void union(int p, int q)//将p所在子树的根节点的父节点设为q所在子树的根节点
{
int i = root(p);
int j = root(q);
id[i] = j;
}
}

各个操作的时间复杂度:注意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中容易出现树很高的情况。

实现过程:

 public class WeightedQuickUnionUF {
private int[] id,sz; public WeightedQuickUnionUF(int N)
{
id = new int[N];
sz = new int[N];//记录以i为根节点的树的节点个数
for (int i = 0; i < N; i++)
{
sz[i] = 1;
id[i] = i;
}
} private int root(int i)//和quick union相同
{
while (i != id[i]) i = id[i];
return i;
} public boolean connected(int p, int q)//和quick union相同
{
return root(p) == root(q);
} public void union(int p, int q)
{
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];}
}
}

各个函数的时间复杂度:注意到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:

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

方式2:

     private int root(int i)
{
while (i != id[i])
{
id[i] = id[id[i]];//指向父节点的父节点
i = id[i];
}
return i;
}

对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. vim出现“E212: Can't open file for writing”的处理办法

    在使用vim 对文件或配置进行编辑的时候,在保存时发现当前用户没有写权限.又不想放弃当前编辑的内容,怎么办呢? 来自stackoverflow “For some reason the file yo ...

  2. C#基础笔记(第二十一天)

    1.FIle类.Path类.Directory类复习操作文件的File 操作文件,静态类,对文件整体操作.拷贝.删除.剪切等.Directory 操作目录(文件夹),静态类.Path 对文件或目录的路 ...

  3. Mycat SqlServer 技术栈 实现 主从分离

    先说明下版本:SqlServer2008R2 + MyCat 1.6 现在主从分离 一主一从 用的是 代码 写死的方式  转换下思路 一主两从 或者多从 怎么实现 负载均衡 或者 按权重调用相应库呢 ...

  4. Tomcat绿色版启动"startup.bat"一闪问题的解决方法!

    进入DOS窗口,运行"startup.bat",会出现错误提示,我是win7 64位,提示“JRE_HOME”设置不正确.于是进入环境变量配置,设置“JRE_HOME”项,随后保存 ...

  5. 【BZOJ2440】[中山市选2011]完全平方数

    题意描述 原题 一句话描述: 求第K个不是完全平方数的倍数的数. K≤$10^{9}$ ------------------------------------------ 题解: 首先,直接求第$k ...

  6. 关于gcd和exgcd的一点心得,保证看不懂(滑稽)

    网上看了半天……还是没把欧几里得算法和扩展欧几里得算法给弄明白…… 然后想了想自己写一篇文章好了…… 参考文献:https://www.cnblogs.com/hadilo/p/5914302.htm ...

  7. Python dict转化为string方法

    dict-->string: str() string-->dict eval()(这个只是网上看的,没实测)

  8. [javascript]—jQuery解析本地 XML 文档

    Create a jQuery object using an XML string and obtain the value of the title node. <!doctype html ...

  9. AI 的下一个重大挑战:理解语言的细微差别

    简评:人类语言非常博大精妙,同一句话在不同的语境下,就有不同的含义.连人类有时候都不能辨别其中细微的差别,机器能吗?这就是人工智能的下一个巨大挑战:理解语言的细微差别.本文原作者是 Salesforc ...

  10. 编程大牛 Bruce Eckel 对新程序员的忠告

    简评:作者 Bruce Eckel 是编程界的大牛,著有大名鼎鼎的<Thinking in C++>和<Thinking in Java>.本文是他对程序员(尤其是新手)的忠告 ...