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过程举例
数组存储连接情况,如下图所示若第i个元素与第j个元素相连接,则id[i]=id[j]
这种方法的一个Union命令的执行需要访问id[]数组N次,过于复杂
当一个元素i,id[i]=i时,i为root
利用树的结构,每次union(p,q)的时候只将p所在的组的root的值改为q所在组的root的值
判断connect时,若root(p)==root(q),则认为两者是连通的
所以想建立尽量平衡的树,所有有以下改进
QuickUnion方法不管p和q所在树的大小直接把p所在的root挂在q的root上
通过weight方法判断p和q的所在树的大小,将较小的树挂在较大的树上,这样会实现尽量的平衡
为了记录树的大小引入sz[]数组,sz[i]表示以i为root的树的大小(即有多少个元素),在union函数中修改sz[]
任何一个元素x的深度不会大于lgN,lg表示以2为底取对数(因为树最坏的情况是二叉的,每层元素少,所以深度会较深)
有两种实现方法
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
从上到下的渗透,白色的格子表示连通区域,白色的格子越多,从上到下渗透的可能性越大
求这样一个白色格子所占比例p的临界值,当大于p时有很大的可能性连通
利用蒙特卡罗估计方法,现将N*N的格子全部置黑,然后每一次随机置白一个格子(union过程),计算从最顶层元素到最低层元素是否连通(判断connect过程)
计算过程中,不用依次计算每一个顶层格子到底层格子是否连通,直接将所有的顶层连接到一个虚拟的root,将底层连接到另一虚拟的root上,每次只判断两个root是否连通即可,通过多次反复试验,估计p值
课程视频的地址: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值
相关文章推荐
- 普林斯顿算法课Part 1 Week 1 Union−Find
- Coursera Algorithms, Part 1 Week 1: Union-Find
- Princeton Algorithms: Part 1 [week 1:Union Find]
- Stanford - Algorithms: Design and Analysis, Part 1 - Week 3 Assignment: Contraction
- Stanford - Algorithms: Design and Analysis, Part 2 - Week 2 Assignment: Clustering
- Stanford: Algorithms: Design and Analysis, Part 1 [Week 2]
- Stanford - Algorithms: Design and Analysis, Part 1 - Week 2 Assignment: QuickSort
- Stanford - Algorithms: Design and Analysis, Part 1 - Week 4 Assignment: strongly connected component
- Stanford - Algorithms: Design and Analysis, Part 1 - Week 5 Assignment: Dijkstra
- 跟着Sedgewick学算法(week 1 UnionFind)
- 普林斯顿算法课Part 1 Week 1 Analysis of Algorithms
- Stanford - Algorithms: Design and Analysis, Part 1 - Week 1 Assignment: number of inversions
- 【Java、算法】Princeton Algorithms Part I Week 1 Exercise
- Week 1 Assignment - Wordnet - Princeton - Algorithms Part II
- Stanford - Algorithms: Design and Analysis, Part 1 - Week 6 Assignment: hash table and heap
- 并查集(Union-Find)算法介绍 Algorithm 4th Part 1
- Stanford - Algorithms: Design and Analysis, Part 2 - Week 1 Assignment: Greedy and Prim
- week 1 Union-Find(并查集)
- 数据结构《14》----并查集 Union-Find
- Union-Find 按大小求并算法