< Summary

Information
Class: MoreStructures.DisjointSets.PathCompressionWeightedQuickUnionDisjointSet
Assembly: MoreStructures
File(s): /home/runner/work/MoreStructures/MoreStructures/MoreStructures/DisjointSets/PathCompressionWeightedQuickUnionDisjointSet.cs
Line coverage
100%
Covered lines: 23
Uncovered lines: 0
Coverable lines: 23
Total lines: 85
Line coverage: 100%
Branch coverage
100%
Covered branches: 10
Total branches: 10
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
Find(...)100%10100%

File(s)

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

#LineLine coverage
 1namespace MoreStructures.DisjointSets;
 2
 3/// <summary>
 4/// A <see cref="WeightedQuickUnionDisjointSet"/> refinement which improves the performance of the data structure by
 5/// performing a technique known as <b>path compression</b>.
 6/// </summary>
 7/// <remarks>
 8/// This variant of <see cref="WeightedQuickUnionDisjointSet"/> introduces a refinement of the
 9/// <see cref="IDisjointSet.Find(int)"/> method, inherited by its upper classes.
 10/// <br/>
 11/// The <see cref="Find(int)"/> algorithm remains unchanged in its core.
 12/// <br/>
 13/// However, it produces a flatter forest as side-effect, every time is executed on a value.
 14/// <br/>
 15/// Check the documentation of <see cref="Find(int)"/> for further details.
 16/// </remarks>
 17public class PathCompressionWeightedQuickUnionDisjointSet : WeightedQuickUnionDisjointSet
 18{
 19    /// <inheritdoc/>
 3720    public PathCompressionWeightedQuickUnionDisjointSet(int valuesCount) : base(valuesCount)
 3521    {
 3522    }
 23
 24    /// <inheritdoc path="//*[not(self::remarks)]"/>
 25    /// <remarks>
 26    ///     <para id="algorithm">
 27    ///     ALGORITHM
 28    ///     <br/>
 29    ///     - The algorithm is pretty much like <see cref="QuickUnionDisjointSet.Find(int)"/>, with one main
 30    ///       difference.
 31    ///       <br/>
 32    ///     - The difference lies in <b>path compression</b>: once the root of the tree is found, a second traversal,
 33    ///       from the <paramref name="value"/> up to its root, is performed.
 34    ///       <br/>
 35    ///     - During the second traversal, each node in path is directly attached to the root.
 36    ///       <br/>
 37    ///     - That keeps the disjoint set equivalent to its previous state, by transitivity of the equivalence
 38    ///       relationship.
 39    ///       <br/>
 40    ///     - However, it makes the tree much more flat, and the average height of all the nodes in the forest smaller.
 41    ///       <br/>
 42    ///     - That means that future <see cref="Find(int)"/>, but also <see cref="IDisjointSet.Union(int, int)"/> and
 43    ///       <see cref="IDisjointSet.AreConnected(int, int)"/>, will be much faster, since it's faster to reach the
 44    ///       root of each tree.
 45    ///     </para>
 46    ///     <para id="complexity">
 47    ///     COMPLEXITY
 48    ///     <br/>
 49    ///     - Find the root takes a time proportional to the height of the tree, the item is in.
 50    ///       <br/>
 51    ///     - Because path compression keeps trees very flat, incrementing the fan out, while the complexity is not
 52    ///       constant and there is definitely a dependence over n, it is a sub-logarithmic dependency.
 53    ///       <br/>
 54    ///     - More precisely, Time Complexity is O(log*(n)), which can be considered "pseudo-constant" for any
 55    ///       "real world" value of n.
 56    ///       <br/>
 57    ///     - Space Complexity remains O(1), since only a constant amount of additional space is required to run the
 58    ///       algorithm.
 59    ///     </para>
 60    /// </remarks>
 61    public override int Find(int value)
 25562    {
 25563        if (ValuesCount == 0)
 164            throw new InvalidOperationException(
 165                $"{nameof(AreConnected)} cannot be invoked on an empty set.");
 25466        if (value < 0 || value >= ValuesCount)
 367            throw new ArgumentException(
 368                $"Must be non-negative and smaller than {nameof(ValuesCount)}.", nameof(value));
 69
 25170        var root = value;
 32371        while (Parents[root] != root)
 7272        {
 7273            root = Parents[root];
 7274        }
 75
 32376        while (Parents[value] != value)
 7277        {
 7278            var parent = Parents[value];
 7279            Parents[value] = root;
 7280            value = parent;
 7281        }
 82
 25183        return root;
 25184    }
 85}