Java 带路径压缩算法的加权快速并集
有一种“带路径压缩的加权快速并集”算法 守则:Java 带路径压缩算法的加权快速并集,java,algorithm,union-find,Java,Algorithm,Union Find,有一种“带路径压缩的加权快速并集”算法 守则: 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++) { i
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];
}
}
}
公共类权重dqu
{
私有int[]id;
私有int[]iz;
公共权重QU(整数N)
{
id=新的整数[N];
iz=新整数[N];
for(int i=0;i
问题:
id[i]=id[id[i]
意味着我们只到达节点的第二个节点,而不是根节点iz[]
包含从0
到N-1
的整数。iz[]
如何帮助我们知道集合中元素的数量有人能帮我澄清一下吗?首先要了解
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
这是正确的版本:
for(int i = 0; i < id.length; i++)
{
iz[i] = 1; // RIGHT
id[i] = i;
}
for(int i=0;i
iz[i]
是以i
为根的树的元素数(或者如果i
不是根,则iz[i]
未定义)。因此它应该初始化为1
,而不是i
。最初,每个元素都是一个大小为1
问题1的独立“单体”树。
说行id[i]=id[id[i]]是不对的;仅到达根的第二个祖先。您将认识到,while循环while(i!=id[i])仅在节点i指向根时停止,即当i==id[i]时。此时,我们将使用线id[i]=id[i]]将节点指向根;其中,内部id[i]是根
问题2
初始化iz[i]=i是错误的;实际上它应该是iz[i]=1;也就是说,每个节点大小在开始时都由1初始化,因为它们的大小为1。
在并集函数中,你会发现我们有直线iz[j]+=iz[i];和iz[i]+=iz[j];它将根节点的大小更新为连接在一起的两个组件的大小之和。这将有效地更新节点大小。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;
}
/**
*返回包含站点p的组件的组件标识符。
*@param p表示一个站点的整数
*@返回包含站点p的组件的组件标识符
*@throws java.lang.IndexOutOfBoundsException,除非0还有一点需要注意:
当我们在做id[i]=id[id[i]]
i.e;让我成为它的祖父母
-然后,id[i]
的大小将减小i,e的大小<代码>iz[id[i]]-=iz[i]
现在,这使得代码完全正确
我对此不确定,但直觉上我觉得,
它的缺失不会引起问题,因为我们总是比较根的大小。阅读c/c++中的算法,第1-4部分,robert sedgewick,第1章,很好的解释。关于路径压缩,这是路径压缩的一种单遍变体,使路径中的每一个节点指向其祖辈节点(将路径长度减半)两次传递更像是在root()中添加第二个循环,将每个被检查节点的id[]设置为root。似乎有必要补充一下。