www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Code review - disjoint sets

Hello. Is code-review requests welcome in this forum? If so I 
would like some criticisms and feedback for my disjoint sets 
implementation. The code is as follows:

module dsets;

/// dsets is an implementation of disjoint sets. It is implemented
/// with a simple class. To construct it, you provide the maximum 
node
/// number.
/// Limitation: CANNOT DISCONNECT TWO NODES

/// If the array is big enough, opt for parallel operations if 
possible
immutable ulong minimumParallelArrayLength = 10_000;

public class DSets
{
private:
     ulong[] ids, heights;

     bool isRoot(const ulong n) const
     {
         return ids[n] == n;
     }

public:
     /// A `DSets(10)` would create a disjoint set of 0 to 10
     /// inclusive.
     this(in ulong maxN)
     {
         ids.reserve(maxN + 1);
         heights.reserve(maxN + 1);

         foreach (n; 0 .. maxN + 1)
         {
             ids ~= n;
             heights ~= 0;
         }
     }

     /// Returns the root id of a given node
     ulong getRoot(in ulong n) const
     {
         ulong result = n;
         while (ids[result] != result)
             result = ids[ids[result]]; // path compression
         return result;
     }

     /// Connect two nodes. Does not check membership so may throw
     /// errors
     void connect(in ulong n, in ulong m)
     {
         auto nRoot = getRoot(n), mRoot = getRoot(m);
         if (nRoot != mRoot)
         {
             if (heights[nRoot] >= heights[mRoot])
             {
                 ids[mRoot] = ids[nRoot];
                 heights[nRoot] += heights[mRoot];
             }
             else
             {
                 ids[nRoot] = ids[mRoot];
                 heights[mRoot] += heights[nRoot];
             }
         }
     }

     /// Check if two given nodes are connected.
     bool connected(in ulong n, in ulong m) const
     {
         return getRoot(n) == getRoot(m);
     }

     /// Returns the number of nodes in the set
     ulong length() const  safe
     {
         return ids.length;
     }

     /// Add a node
     void grow(in ulong nodes = 0)
     {
         auto toAdd = ids[$ - 1];
         foreach (_; 0 .. nodes + 1)
         {
             ids ~= toAdd++;
             heights ~= 0;
         }
     }

     /// Get an array of roots
     ulong[] getRoots() const
     {
         if (ids.length == 0)
             return [];

         // D does not have a standard hash-set. The
         // workaround is to use a hash-table
         bool[ulong] roots;

         // premature optimization, if the array is not huge,
         // do not opt for multithreaded operation
         if (ids.length < 10_000)
         {
             foreach (i, id; ids)
                 if (ids[i] == i)
                     if (!(i in roots))
                         roots[i] = true;
         }
         else
         {
             import std.parallelism : parallel;

             foreach (i, id; ids.parallel())
                 if (ids[i] == i)
                     if (!(i in roots))
                         roots[i] = true;
         }
         return roots.keys;
     }

     /// Returns all the nodes connected to the given node
     ulong[] getLinkedNodes(in ulong node) const
     {
         // premature optimization, if the array is not huge,
         // do not opt for multithreaded operation
         ulong[] nodes;
         if (ids.length < 10_000)
         {
             foreach (i, _; ids)
                 if (this.connected(node, i))
                     nodes ~= i;
         }
         else
         {
             import std.parallelism : parallel;

             foreach (i, _; ids.parallel())
                 if (this.connected(node, i))
                     nodes ~= i;
         }
         return nodes;
     }
}

unittest
{
     import std.stdio;

     writefln("Testing %s...", __FILE__);
     scope (success)
         writeln("Success");

     auto forrest = new DSets(9);

     forrest.connect(9, 3);
     forrest.connect(1, 3);
     forrest.connect(9, 0);
     forrest.connect(7, 5);
     forrest.connect(6, 4);
     assert(forrest.connected(1, 0));
     assert(forrest.connected(3, 0));
     assert(!forrest.connected(5, 4));

     foreach (root; forrest.getRoots())
         writeln(root, " ==> ", forrest.getLinkedNodes(root));
}


outupt:

$ dub test -q
Testing source/dsets.d...
6 ==> [4, 6]
7 ==> [5, 7]
2 ==> [2]
1 ==> [0, 1, 3, 9]
8 ==> [8]
Success
Dec 07 2018