using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Advanced.Algorithms.DataStructures
{
///
/// A disjoint set implementation.
///
public class DisJointSet : IEnumerable
{
///
/// A Map for faster access for members.
///
private Dictionary> set
= new Dictionary>();
public int Count { get; private set; }
///
/// Creates a new set with given member.
/// Time complexity: log(n).
///
public void MakeSet(T member)
{
if (set.ContainsKey(member))
{
throw new Exception("A set with given member already exists.");
}
var newSet = new DisJointSetNode()
{
Data = member,
Rank = 0
};
//Root's Parent is Root itself
newSet.Parent = newSet;
set.Add(member, newSet);
Count++;
}
///
/// Returns the reference member of the set where this member is part of.
/// Time complexity: log(n).
///
public T FindSet(T member)
{
if(!set.ContainsKey(member))
{
throw new Exception("No such set with given member.");
}
return FindSet(set[member]).Data;
}
///
/// Recursively move up in the set tree till root
/// and return the Root.
/// Does path Compression on all visited members on way to root
/// by pointing their parent to Root.
///
private DisJointSetNode FindSet(DisJointSetNode node)
{
var parent = node.Parent;
if(node !=parent)
{
//compress path by setting parent to Root
node.Parent = FindSet(node.Parent);
return node.Parent;
}
//reached root so return the Root (reference Member)
return parent;
}
///
/// Union's given member's sets if given members are in differant sets.
/// Otherwise does nothing.
/// Time complexity: log(n).
///
public void Union(T memberA, T memberB)
{
var rootA = FindSet(memberA);
var rootB = FindSet(memberB);
if(rootA.Equals(rootB))
{
return;
}
var nodeA = set[rootA];
var nodeB = set[rootB];
//equal rank so just pick any of two as Root
//and increment rank
if(nodeA.Rank == nodeB.Rank)
{
nodeB.Parent = nodeA;
nodeA.Rank++;
}
else
{
//pick max Rank node as root
if(nodeA.Rank < nodeB.Rank)
{
nodeA.Parent = nodeB;
}
else
{
nodeB.Parent = nodeA;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator GetEnumerator()
{
return set.Values.Select(x => x.Data).GetEnumerator();
}
}
internal class DisJointSetNode
{
internal T Data { get; set; }
internal int Rank { get; set; }
internal DisJointSetNode Parent { get; set; }
}
}