当前位置: 首页 > 知识库问答 >
问题:

带路径压缩算法的加权快速并集

戚晨
2023-03-14

有一种“带路径压缩的加权快速联合”算法。

代码

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[] 包含从 0N-1 的整数。iz[]如何帮助我们知道集合中元素的数量?

    有人能帮我澄清一下吗?

  • 共有3个答案

    彭飞虎
    2023-03-14

    这里还有一点需要注意:

    当我们创建id[i]=id[id[i]]i;让我在它的祖父母手下

    -则 id[i] 的大小将减小 i i,e 的大小;iz[id[i]]-=iz[i]

    这使得代码完全正确。

    我不确定这一点,但直觉上我觉得,它的缺失不会导致问题,因为我们总是在比较根的大小。

    许波涛
    2023-03-14

    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

    尚声
    2023-03-14

    首先了解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[] 包含从 0N-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个学生是彼此的直