有一种“带路径压缩的加权快速联合”算法。
代码:
public class WeightedQU
{
private int[] id;
private int[] iz;
public WeightedQU(int N)
{
id = new int[N];
iz = new int[N];
for(int i = 0; i < id.length; i++)
{
iz[i] = i;
id[i] = i;
}
}
public int root(int i)
{
while(i != id[i])
{
id[i] = id[id[i]]; // this line represents "path compression"
i = id[i];
}
return i;
}
public boolean connected(int p, int q)
{
return root(p) == root(q);
}
public void union(int p, int q) // here iz[] is used to "weighting"
{
int i = root(p);
int j = root(q);
if(iz[i] < iz[j])
{
id[i] = j;
iz[j] += iz[i];
}
else
{
id[j] = i;
iz[i] += iz[j];
}
}
}
问题:
>
路径压缩是如何工作的id[i]=id[id[i]]
意味着我们只到达节点的第二个祖先,而不是根。
iz[]
包含从 0
到 N-1 的
整数。iz[]
如何帮助我们知道集合中元素的数量?
有人能帮我澄清一下吗?
这里还有一点需要注意:
当我们创建id[i]=id[id[i]]
i;让我在它的祖父母手下
-则 id[i]
的大小将减小 i i,e 的大小;iz[id[i]]-=iz[i]
这使得代码完全正确。
我不确定这一点,但直觉上我觉得,它的缺失不会导致问题,因为我们总是在比较根的大小。
id[i]=id[id[i]];//这一行表示“路径压缩”
上面的代码是联合查找(Kevin Wayne和Robert Sedgewick的算法,第一部分)幻灯片中提到的“更简单的一次变体”。因此,您对问题1的猜测是正确的。每个被检查的节点都指向它的祖父母。
要使每个被检查的节点指向根,我们需要两次传递实现:
/**
* Returns the component identifier for the component containing site <tt>p</tt>.
* @param p the integer representing one site
* @return the component identifier for the component containing site <tt>p</tt>
* @throws java.lang.IndexOutOfBoundsException unless 0 <= p < N
*/
public int find(int p) {
int root = p;
while (root != id[root])
root = id[root];
while (p != root) {
int newp = id[p];
id[p] = root;
p = newp;
}
return root;
}
参考编号:http://algs4.cs.princeton.edu/15uf/WeightedQuickUnionPathCompressionUF.java.html
首先了解id
是一个森林。id[i]
是i
的父级。如果id[i]==i
则表示i
是一个根。
对于某些根i
(其中id[i]==i
),则iz[i]
是以i
为根的树中的元素数。
public int root(int i)
{
while(i != id[i])
{
id[i] = id[id[i]]; // this line represents "path compression"
i = id[i];
}
return i;
}
路径压缩的工作原理是什么?id[i] = id[id[i]
意味着我们只到达节点的第二个祖先,而不是根。
当我们沿着树向上寻找根时,我们将节点从它们的父节点移动到它们的父节点。这部分展平了树。注意,这个操作并没有改变节点是哪个树的成员,这是我们唯一感兴趣的。这就是路径压缩技术。
(你确实注意到了这个循环吗?而(i == id[i])
一旦 i
是根节点就终止)
iz[]
包含从 0
到 N-1 的
整数。iz[]
如何帮助我们知道集合中元素的数量?
代码中有转录错误:
for(int i = 0; i < id.length; i++)
{
iz[i] = i; // WRONG
id[i] = i;
}
这是正确的版本:
for(int i = 0; i < id.length; i++)
{
iz[i] = 1; // RIGHT
id[i] = i;
}
< code>iz[i]是以< code>i为根的树的元素数(或者,如果< code>i不是根,则< code>iz[i]未定义)。所以应该初始化为< code>1,而不是< code>i。最初,每个元素是一个大小为< code>1的单独的“单例”树。
根据Princeton booksite,带有路径压缩的加权快速联合将10^9联合对10^9对象的操作时间从一年减少到大约6秒。这个数字是怎么得出的?当我在10^8操作中运行下面的代码时,我的运行时间是61s。
我有一个项目,我必须实现一个带有路径压缩算法的加权快速并集。在看到其他一些源代码后,我最终得到了这个: 分配给我的任务是正确完成以下方法: int find(int v) void unite(int v,int u) setCount(int v) 嗯,算法似乎很慢,我找不到合适的解决方案。
我正在为联合/查找结构实现快速联合算法。在“Java中的算法”一书网站上给出的实现中,普林斯顿实现在实现路径压缩(在方法中)时无法保持树的大小不变。这不应该对算法产生不利影响吗?还是我错过了什么?另外,如果我是对的,我们将如何修改大小数组?
我正在学习联合/查找结构的“加权快速联合与路径压缩”算法。普林斯顿edu网站详细解释了该算法。这是Java的实现: 但就像网站提到它的性能一样: 定理:从空数据结构开始,任何 M 并集序列和对 N 个对象的查找操作都需要 O(N M lg* N) 时间。 证明非常困难。 但是算法仍然很简单! 但我仍然很好奇迭代对数lg*n是如何产生的。它是如何推导出来的?有人可以证明它或只是以直观的方式解释它吗?
针对并集寻找不相交集的问题,提出了带路径压缩的加权快速并集算法 带路径压缩算法的加权快速并集 路径压缩会影响iz[]数组(包含以I为根的树的长度的数组)吗?
处理以下问题(https://leetcode.com/problems/friend-circles/): 一个班有N个学生。他们有些是朋友,有些不是。他们的友谊本质上是可传递的。比如A是B的直接好友,B是C的直接好友,那么A就是C的间接好友,而我们定义的朋友圈就是一群直接或者间接好友的同学。 给定一个N*N矩阵M,表示班级学生之间的朋友关系。如果M[i][j]=1,则第i和第j个学生是彼此的直