您的位置:首页 > 编程语言 > Go语言

Union-find(Algorithms, Part 1, week 1 )

2014-09-18 13:12 513 查看
最近开始在Coursera上听公开课, Princeton的算法课感觉挺不错的,鉴于自己原来欠下了太多技术债务,决定好好努力,争取能够跟下来,每堂课会总结记录一点东西

课程视频的地址:https://class.coursera.org/algs4partI-006/lecture, 感谢Coursera提供了这么好的一个平台

中文相关资料:http://blog.csdn.net/dm_vincent/article/details/7655764

union-find算法翻译成中文有的叫并查集/联合查找算法,主要实现判断两个节点之间是否有通路,

如下图所示union(4,3)在4和3之间建立连接,connected(0,7)判断0和7之间是否由有连接

连接具有对称性和传递性

(1)p->q, 则q->p

 (2) p->q,q->r,则p->r



uion过程举例



Union-Find的API接口



1.Quick-Find

设元素个数为N,利用id
数组存储连接情况,如下图所示若第i个元素与第j个元素相连接,则id[i]=id[j]



public class QuickFindUF
{

private int id[];

//初始化 id数组
public QuickFindUF(int N)
{
id=new int
;
for(int i=0;i<N;i++)
{
id[i]=i;
}
}

public boolean Connect(int p,int q)
{
return (id[p]==id[q]);
}

//将所有id[]中与pid相同的置为qid
public void Union(int p,int q)
{
int pid=id[p];
int qid=id[q];

if(pid!=qid)
{
for(int i=0;i<id.length;i++)
{
if(id[i]==pid)
{
id[i]=qid;
}
}
}
}

}


这种方法的一个Union命令的执行需要访问id[]数组N次,过于复杂

2.Quick-Union



当一个元素i,id[i]=i时,i为root
利用树的结构,每次union(p,q)的时候只将p所在的组的root的值改为q所在组的root的值
判断connect时,若root(p)==root(q),则认为两者是连通的
public class QuickUnionUF
{
private int id[];

//初始化 id数组
public QuickUnionUF(int N)
{
id=new int
;
for(int i=0;i<N;i++)
{
id[i]=i;
}
}

//返回元素i的root节点
private int root(int p)
{
while(id[p]!=p)
{
p=id[p];
}
return p;
}
public boolean Connect(int p,int q)
{
return (root(p)==root(q));
}

//修改p所在组的root,将id[root(p)]=root(q)
public void Union(int p,int q)
{
int i=root(p);
int j=root(q);
id[i]=j;
}
}

3.Improvement

QuickUnion方法建立的树可能会很高,最坏情况是一个链表状的,这样每次在判断connect,寻找root的时候就会比较耗时
所以想建立尽量平衡的树,所有有以下改进

(1)Improvement 1:weighting



QuickUnion方法不管p和q所在树的大小直接把p所在的root挂在q的root上
通过weight方法判断p和q的所在树的大小,将较小的树挂在较大的树上,这样会实现尽量的平衡
为了记录树的大小引入sz[]数组,sz[i]表示以i为root的树的大小(即有多少个元素),在union函数中修改sz[]



任何一个元素x的深度不会大于lgN,lg表示以2为底取对数(因为树最坏的情况是二叉的,每层元素少,所以深度会较深)

(2)Improvement 2:path compression

 在寻找节点p的root后,将经过的路径中的每一个节点都直接挂在root下



有两种实现方法
1. 在root函数中直接在找root的while循环后再加一层循环,将p到root途经的每一个节点都直接指向root
2.直接在root的while循环中修改,将其指向它的grandpa节点~(不如第一种方法彻底,但是也会压缩路径)

M次操作的复杂度:



lg*运算代表迭代取lg运算 while(lgN>1){ N=lgN; i++}  e.g. lg*65536=5

4.应用

连通性的估计



从上到下的渗透,白色的格子表示连通区域,白色的格子越多,从上到下渗透的可能性越大



求这样一个白色格子所占比例p的临界值,当大于p时有很大的可能性连通

利用蒙特卡罗估计方法,现将N*N的格子全部置黑,然后每一次随机置白一个格子(union过程),计算从最顶层元素到最低层元素是否连通(判断connect过程)
计算过程中,不用依次计算每一个顶层格子到底层格子是否连通,直接将所有的顶层连接到一个虚拟的root,将底层连接到另一虚拟的root上,每次只判断两个root是否连通即可,通过多次反复试验,估计p值

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法