1.5.3

1.5.3 #

解答 #

加权 quick-union 的官方实现:WeightedQuickUnionUF.java

样例输出:

1 2 3 4 5 6 7 8 9 数组访问:3
1 2 3 3 5 6 7 8 9 数组访问:3
1 2 3 3 5 6 7 5 9 数组访问:3
1 7 3 3 5 6 7 5 9 数组访问:3
7 7 3 3 5 6 7 5 9 数组访问:5
7 7 3 3 7 6 7 5 9 数组访问:3
7 7 9 3 7 6 7 5 9 数组访问:5
7 7 9 3 7 6 7 5 7 数组访问:9

代码 #

WeightedQuickUnionUF.cs,这个类继承了 QuickUnion.cs,重新实现了 Union() 和 Find() 等方法。

关于 QuickUnion.cs 可以参见 1.5.2 的代码部分。

public class WeightedQuickUnionUf : QuickUnionUf
{
    /// <summary>
    /// 记录各个树大小的数组。
    /// </summary>
    /// <value>记录各个树大小的数组。</value>
    protected int[] Size;

    /// <summary>
    /// 记录 parent 数组的访问次数的计数器。
    /// </summary>
    /// <value>parent 数组的访问次数。</value>
    public int ArrayParentVisitCount { get; private set; }
    /// <summary>
    /// 记录 size 数组的访问次数的计数器。
    /// </summary>
    /// <value>size 数组的访问次数。</value>
    public int ArraySizeVisitCount { get; private set; }

    /// <summary>
    /// 建立使用加权 quick-union 的并查集。
    /// </summary>
    /// <param name="n">并查集的大小。</param>
    public WeightedQuickUnionUf(int n) : base(n)
    {
        Size = new int[n];
        for (var i = 0; i < n; i++)
        {
            Size[i] = 1;
        }
        ArrayParentVisitCount = 0;
        ArraySizeVisitCount = 0;
    }

    /// <summary>
    /// 清零数组访问计数。
    /// </summary>
    public override void ResetArrayCount()
    {
        ArrayParentVisitCount = 0;
        ArraySizeVisitCount = 0;
    }

    /// <summary>
    /// 获取 size 数组。
    /// </summary>
    /// <returns>返回 size 数组。</returns>
    public int[] GetSize()
    {
        return Size;
    }

    /// <summary>
    /// 寻找一个结点所在的连通分量。
    /// </summary>
    /// <param name="p">需要寻找的结点。</param>
    /// <returns>该结点所属的连通分量。</returns>
    public override int Find(int p)
    {
        Validate(p);
        while (p != Parent[p])
        {
            p = Parent[p];
            ArrayParentVisitCount += 2;
        }
        ArrayParentVisitCount++;
        return p;
    }

    /// <summary>
    /// 将两个结点所属的连通分量合并。
    /// </summary>
    /// <param name="p">需要合并的结点。</param>
    /// <param name="q">需要合并的另一个结点。</param>
    public override void Union(int p, int q)
    {
        var rootP = Find(p);
        var rootQ = Find(q);
        if (rootP == rootQ)
        {
            return;
        }

        if (Size[rootP] < Size[rootQ])
        {
            Parent[rootP] = rootQ;
            Size[rootQ] += Size[rootP];
        }
        else
        {
            Parent[rootQ] = rootP;
            Size[rootP] += Size[rootQ];
        }
        ArrayParentVisitCount++;
        ArraySizeVisitCount += 4;
        TotalCount--;
    }
}

Main 方法

var input = "9-0 3-4 5-8 7-2 2-1 5-7 0-3 4-2".Split(' ');
var weightedQuickUnion = new WeightedQuickUnionUf(10);

foreach (var s in input)
{
    weightedQuickUnion.ResetArrayCount();
    var numbers = s.Split('-');
    var p = int.Parse(numbers[0]);
    var q = int.Parse(numbers[1]);

    weightedQuickUnion.Union(p, q);
    var parent = weightedQuickUnion.GetParent();
    for (var i = 0; i < parent.Length; i++)
    {
        Console.Write(parent[i] + " ");
    }

    Console.WriteLine("数组访问:" + weightedQuickUnion.ArrayParentVisitCount);
}

另请参阅 #

UnionFind 库