1.5.12

1.5.12 #

解答 #

QuickUnionPathCompression 的官方实现:QuickUnionPathCompressionUF.java

在找到根节点之后,再访问一遍 p 到根节点这条路径上的所有结点,将它们直接和根节点相连。

重写过后的 Find() 方法:

/// <summary>
/// 寻找结点所属的连通分量。
/// </summary>
/// <param name="p">需要寻找的结点。</param>
/// <returns>结点所属的连通分量。</returns>
public override int Find(int p)
{
    int root = p;
    while (root != this.parent[root])
    {
        root = this.parent[root];
    }
    while (p != root)
    {
        int newp = this.parent[p];
        this.parent[p] = root;
        p = newp;
    }
    return p;
}

由于路径压缩是在 Find() 方法中实现的,

只要输入保证是根节点两两相连即可构造较长的路径。

代码 #

QuickUnionPathCompressionUF.cs 直接从 QuickUnionUF.cs 继承而来。

关于 QuickUnionUF.cs,参见 1.5.2 的解答。

public class QuickUnionPathCompressionUf : QuickFindUf
{
    /// <summary>
    /// 新建一个大小为 n 的并查集。
    /// </summary>
    /// <param name="n">新建并查集的大小。</param>
    public QuickUnionPathCompressionUf(int n) : base(n) { }

    /// <summary>
    /// 寻找结点所属的连通分量。
    /// </summary>
    /// <param name="p">需要寻找的结点。</param>
    /// <returns>结点所属的连通分量。</returns>
    public override int Find(int p)
    {
        var root = p;
        while (root != Parent[root])
        {
            root = Parent[root];
        }
        while (p != root)
        {
            var newp = Parent[p];
            Parent[p] = root;
            p = newp;
        }
        return p;
    }
}

Main 方法

var uf = new QuickUnionPathCompressionUf(10);

// 使用书中提到的最坏情况,0 连 1,1 连 2,2 连 3……
for (var i = 0; i < 4; i++)
{
    uf.Union(i, i + 1);
}

var id = uf.GetParent();
for (var i = 0; i < id.Length; i++)
{
    Console.Write(id[i]);
}

Console.WriteLine();

另请参阅 #

UnionFind 库