// union-find.h++
// Copyright © 2011 Jordi Gutiérrez Hermoso
// Author: Jordi Gutiérrez Hermoso
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of the
// License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.n
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
#include
#include
using std::unordered_map;
using std::list;
// T - type of object we're union-finding for
// H - hash for the map
template >
class union_find
{
//Dramatis personae
private:
//Each root has rank.
unordered_map num_ranks;
//Each object points to its parent, possibly itself.
unordered_map parent_pointers;
//Represent each object by a number and vice versa.
unordered_map num_to_objects;
unordered_map objects_to_num;
// Act 1
public:
//Insert a collection of objects
void insert_objects (const list& objects)
{
for (auto i = objects.begin (); i != objects.end (); i++)
{
find (*i);
}
}
//Give the root representative id for this object, or insert into a
//new set if none is found
octave_idx_type find_id (const T& object)
{
//Insert new element if not found
if (objects_to_num.find (object) == objects_to_num.end () )
{
//Assign number serially to objects
octave_idx_type obj_num = objects_to_num.size ()+1;
num_ranks[obj_num] = 0;
objects_to_num[object] = obj_num;
num_to_objects[obj_num] = object;
parent_pointers[obj_num] = obj_num;
return obj_num;
}
//Path from this element to its root, we'll build it.
list path (1, objects_to_num[object]);
octave_idx_type par = parent_pointers[path.back ()];
while ( par != path.back () )
{
path.push_back (par);
par = parent_pointers[par];
}
//Update everything we've seen to point to the root.
for (auto i = path.begin (); i != path.end (); i++)
{
parent_pointers[*i] = par;
}
return par;
}
T find( const T& object)
{
return num_to_objects[find_id (object)];
}
//Given two objects, unite the sets to which they belong
void unite (const T& obj1, const T& obj2)
{
octave_idx_type on1 = find_id(obj1), on2 = find_id(obj2);
//Check if any union needs to be done, maybe they already are
//in the same set.
if (on1 != on2)
{
octave_idx_type r1 = num_ranks[on1], r2 = num_ranks[on2];
if ( r1 < r2)
{
parent_pointers[on1] = on2;
num_ranks.erase (on1); //Only root nodes need a rank
}
else if (r2 > r1)
{
parent_pointers[on2] = on1;
num_ranks.erase (on2);
}
else
{
parent_pointers[on2] = on1;
num_ranks.erase (on2);
num_ranks[on1]++;
}
}
}
const unordered_map& get_objects()
{
return objects_to_num;
};
};