< Summary

Information
Class: MoreStructures.DisjointSets.WeightedQuickUnionDisjointSet
Assembly: MoreStructures
File(s): /home/runner/work/MoreStructures/MoreStructures/MoreStructures/DisjointSets/WeightedQuickUnionDisjointSet.cs
Line coverage
100%
Covered lines: 28
Uncovered lines: 0
Coverable lines: 28
Total lines: 108
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
get_Ranks()100%1100%
.ctor(...)100%1100%
GetRanks()100%1100%
Union(...)100%12100%

File(s)

/home/runner/work/MoreStructures/MoreStructures/MoreStructures/DisjointSets/WeightedQuickUnionDisjointSet.cs

#LineLine coverage
 1namespace MoreStructures.DisjointSets;
 2
 3/// <summary>
 4/// A <see cref="QuickUnionDisjointSet"/> refinement which improves the performance of Find by minimizing the height of
 5/// trees in the forest when merging them in <see cref="Union"/>.
 6/// </summary>
 7/// <remarks>
 8/// By merging by rank, the increment of rank of the trees in the forest when merging is minimized, and the forest
 9/// is kept as flat as possible after the <see cref="Union(int, int)"/> operation.
 10/// <br/>
 11/// Keeping trees flat is the way to ensure sub-linear, Time Complexity in
 12/// <see cref="QuickUnionDisjointSet.AreConnected(int, int)"/> and <see cref="QuickUnionDisjointSet.Find(int)"/>, which
 13/// in the specific case become logarithmic in time.
 14/// </remarks>
 15public class WeightedQuickUnionDisjointSet : QuickUnionDisjointSet
 16{
 17    /// <summary>
 18    /// Maps the i-th item of the Disjoint Set to its rank in the tree structure, they belong to.
 19    /// <br/>
 20    /// I-th items which are leaves have rank equal to 0.
 21    /// </summary>
 22    /// <remarks>
 23    /// The rank of a node in the tree is an upper bound for its height.
 24    /// <br/>
 25    /// Ranks are used, instead of heights, because keeping ranks correct is easier than keeping heights correct.
 26    /// </remarks>
 66827    protected int[] Ranks { get; }
 28
 29    /// <inheritdoc path="//*[not(self::summary)]"/>
 30    /// <summary>
 31    /// <inheritdoc/>
 32    /// <br/>
 33    /// Initializes the ranks of all singleton trees to 0.
 34    /// </summary>
 7535    public WeightedQuickUnionDisjointSet(int valuesCount) : base(valuesCount)
 7136    {
 7137        Ranks = new int[valuesCount];
 7138    }
 39
 40    /// <summary>
 41    /// Returns a copy of the ranks of the trees of the forest representing the Disjoint Set.
 42    /// </summary>
 1843    public IList<int> GetRanks() => Ranks.ToArray();
 44
 45    /// <inheritdoc path="//*[not(self::remarks)]"/>
 46    /// <remarks>
 47    ///     <para id="algorithm">
 48    ///     ALGORITHM
 49    ///     <br/>
 50    ///     - It first finds the root R1 of <paramref name="first"/> and the root R2 of <paramref name="second"/>, by
 51    ///       running <see cref="QuickUnionDisjointSet.Find(int)"/> on each item.
 52    ///       <br/>
 53    ///     - Then, it checks the rank of R1, H1 and R2, H2 and uses them to decide whether to attach R1 to R2 or
 54    ///       viceversa.
 55    ///       <br/>
 56    ///     - If <c>H1 >= H2</c>, it attaches R2 as immediate child of R1, by setting the parent of R2 to R1.
 57    ///       <br/>
 58    ///     - Otherwise, it attaches R1 as immediate child of R2, by setting the parent of R1 to R2.
 59    ///       <br/>
 60    ///     - This way the two three now are merged into a single one, which means that all items of the two trees,
 61    ///       including <paramref name="first"/> and <paramref name="second"/> are now in the same set.
 62    ///       <br/>
 63    ///     - Moreover, by merging based on ranks H1 and H2, the rank of the resulting tree is minimized.
 64    ///       <br/>
 65    ///     - Finally the rank of the new root (R1 or R2), is updated, to reflect the merge.
 66    ///     </para>
 67    ///     <para id="complexity">
 68    ///     COMPLEXITY
 69    ///     <br/>
 70    ///     - Find the two roots takes a time proportional to the rank of the two trees.
 71    ///       <br/>
 72    ///     - Thanks to the "merging by rank", unlike in <see cref="QuickUnionDisjointSet"/>, the rank of each tree
 73    ///       in the forest is not O(n) in the worst case, but O(log(n)).
 74    ///       <br/>
 75    ///     - Attaching one root as child of the other is a constant-time operation, since it only requires setting the
 76    ///       parent in the list of parents, which is O(1) work.
 77    ///       <br/>
 78    ///     - Updating the rank of the root of the merged tree is also a constant-time operation.
 79    ///       <br/>
 80    ///     - Therefore, Time Complexity is O(log(n)). Space Complexity is O(1).
 81    ///     </para>
 82    /// </remarks>
 83    public override void Union(int first, int second)
 14084    {
 14085        if (ValuesCount == 0)
 286            throw new InvalidOperationException(
 287                $"{nameof(AreConnected)} cannot be invoked on an empty set.");
 13888        if (first < 0 || first >= ValuesCount)
 489            throw new ArgumentException(
 490                $"Must be non-negative and smaller than {nameof(ValuesCount)}.", nameof(first));
 13491        if (second < 0 || second >= ValuesCount)
 492            throw new ArgumentException(
 493                $"Must be non-negative and smaller than {nameof(ValuesCount)}.", nameof(second));
 94
 13095        var firstRoot = Find(first);
 13096        var secondRoot = Find(second);
 13097        if (Ranks[firstRoot] >= Ranks[secondRoot])
 11598        {
 11599            Parents[secondRoot] = firstRoot;
 115100            Ranks[firstRoot] = Math.Max(Ranks[firstRoot], Ranks[secondRoot] + 1);
 115101        }
 102        else
 15103        {
 15104            Parents[firstRoot] = secondRoot;
 15105            Ranks[secondRoot] = Math.Max(Ranks[secondRoot], Ranks[firstRoot] + 1);
 15106        }
 130107    }
 108}