并查集(Union-Find)算法介绍
2014-10-11 21:18
211 查看
并查集
1.并查集是一种树型的数据结构,用于处理一些不相交集合的合并问题。
并查集的主要操作有
1.合并两个不相交集合(Union(int x,int y))
2.判断两个元素是否属于同一个集合(Find(int x))
3.路径压缩
定义一个数组father,用father[i]表示元素i的父亲结点.
初始化每个集合只有其本身(编号从1-N):
合并操作(Union(int x,int y)),father[i]=j,表示j是i的父亲(即i,j属于同一集合)
查找操作(Find(int x))
查找两个元素是否属于同一集合(father[x]=x表示该元素没有合并过,自身为一个集合)
根据上面就可以写成合并操作了
又如:
上面所有元素最终形成三个集合。
合并操作的改进
最上面的Union的执行是相当任意的,它通过使得第二课棵树的子树而完成合并,对其进行简单的改进是借助任意的方法打破现有的关系,使得总让较小的树成为较大的树的子树,这种方法叫做按大小求并。
进行一次任意的并的结果(分别Union(5,6),Union(7,8),Union(5,7)
后Union(4,5)):
按大小求并的结果:
即总是size小的树作为子树和size大的树进行合并。这样就能够尽量的保持整棵树的平衡。
在初始情况下,每个组的大小都是1,因为只含有一个节点,所以我们可以使用额外的一个数组来维护每个组的大小,对该数组的初始化也很直观:
形象化(上面的文字及此图来自这里):
另一种实现方法为按高度求并,我们跟踪每棵树的高度而不是大小并执行那些Union使得浅点的树成为高点的树的子树,因为只有两棵相同深度的的树求并时树的高度才增加(此时树的高度增加1)。
路径压缩
通过 路径压缩使得结点离根更加的近,一个未采用路径压缩的例子:
路径压缩后:
这样采用路径压缩后使得Find更加的高效。
实现代码:
点这里并查集应用
1.并查集是一种树型的数据结构,用于处理一些不相交集合的合并问题。
并查集的主要操作有
1.合并两个不相交集合(Union(int x,int y))
2.判断两个元素是否属于同一个集合(Find(int x))
3.路径压缩
定义一个数组father,用father[i]表示元素i的父亲结点.
初始化每个集合只有其本身(编号从1-N):
for (int i=1; i<=n; i++) { father[i]=i; }即对于节点i,它的组号也是i。
合并操作(Union(int x,int y)),father[i]=j,表示j是i的父亲(即i,j属于同一集合)
查找操作(Find(int x))
查找两个元素是否属于同一集合(father[x]=x表示该元素没有合并过,自身为一个集合)
int Find(int x) //查找x所属集合 { while (x!=Father[x]) { x=Father[x]; } return Father[x]; }
根据上面就可以写成合并操作了
void Union(int x,int y) { x=Find(x); //查找所属集合 y=Find(y); if(x!=y) //不在同一个集合 { Father[x]=y; //合并 } }
又如:
上面所有元素最终形成三个集合。
合并操作的改进
最上面的Union的执行是相当任意的,它通过使得第二课棵树的子树而完成合并,对其进行简单的改进是借助任意的方法打破现有的关系,使得总让较小的树成为较大的树的子树,这种方法叫做按大小求并。
进行一次任意的并的结果(分别Union(5,6),Union(7,8),Union(5,7)
后Union(4,5)):
按大小求并的结果:
即总是size小的树作为子树和size大的树进行合并。这样就能够尽量的保持整棵树的平衡。
在初始情况下,每个组的大小都是1,因为只含有一个节点,所以我们可以使用额外的一个数组来维护每个组的大小,对该数组的初始化也很直观:
for (int i = 0; i < N; i++) { sz[i] = 1; // 初始情况下,每个组的大小都是1 }而在进行合并的时候,会首先判断待合并的两棵树的大小,然后按照上面图中的思想进行合并,实现代码:
void Union(int x, int y) { int i = find(x); int j = find(y); if (i == j) return; // 将小树作为大树的子树 if (sz[i] < sz[j]) { Father[i] = j; sz[j] += sz[i]; } else { Father[j] = i; sz[i] += sz[j]; } }
形象化(上面的文字及此图来自这里):
另一种实现方法为按高度求并,我们跟踪每棵树的高度而不是大小并执行那些Union使得浅点的树成为高点的树的子树,因为只有两棵相同深度的的树求并时树的高度才增加(此时树的高度增加1)。
void Union(int x,int y) { if(height[x]==height[y]) { height[x]=height[x]+1; Father[y]=x; } else if(height[x]<height[y]) { Father[y]=x; } else { Father[x]=y; } }
路径压缩
通过 路径压缩使得结点离根更加的近,一个未采用路径压缩的例子:
路径压缩后:
这样采用路径压缩后使得Find更加的高效。
实现代码:
int Find(int x) { if(x!=Father[x]) { Father[x]=Find(Father[x]); //递归找根进行更新 } return Father[x]; }
点这里并查集应用
相关文章推荐
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍——转载dm_vincent的博客文章(CSDN blog)
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍 Algorithm 4th Part 1
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍(转)
- 并查集(Union-Find)算法介绍
- 并查集(Union-Find)算法介绍