/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o 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.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package EDU.purdue.cs.bloat.util;
import java.util.*;
/**
* Represents the union-find data structure.
*
* <p>
*
* Sometimes we need to group elements into disjoint sets. Two important
* operations of these sets are finding the set that contains a given element
* ("find") and uniting two sets ("union"). <tt>UnionFind</tt> provides an
* efficient implementation of a data structure that support these operations on
* disjoint sets of integers.
*
* <p>
*
* Each disjoint set is represented by a tree consisting of <tt>Node</tt>s.
* (This <tt>Node</tt> is a class local to <tt>UnionFind</tt> and should not
* be confused with <tt>tree.Node</tt>.) Each <tt>Node</tt> knows its
* parent and child and has a rank associated with it. The parent node is always
* the root node of the set tree. A <tt>Node</tt>'s rank is essentially the
* height of the (sub)tree rooted by that node. When the union of two trees is
* formed, the root with the smaller rank is made to point to the root with the
* larger rank. Naturally, each <tt>Node</tt> has an integer "value"
* associated with it.
*
* <p>
*
* A good description of union-find can be found in [Cormen, et. al. 1990].
*/
public class UnionFind {
// The trees of Nodes that represent the disjoint sets.
ResizeableArrayList nodes;
/**
* Constructor.
*/
public UnionFind() {
nodes = new ResizeableArrayList();
}
/**
* Constructor. Make a <tt>UnionFind</tt> with a given number of disjoint
* sets.
*/
public UnionFind(final int size) {
nodes = new ResizeableArrayList(size);
}
/**
* Searches the disjoint sets for a given integer. Returns the set
* containing the integer a. Sets are represented by a local class
* <tt>Node</tt>.
*/
public Node findNode(final int a) {
nodes.ensureSize(a + 1);
final Node na = (Node) nodes.get(a);
if (na == null) {
// Start a new set with a
final Node root = new Node(a);
root.child = new Node(a);
root.child.parent = root;
nodes.set(a, root.child);
return root;
}
return findNode(na);
}
/**
* Returns the integer value associated with the first <tt>Node</tt> in a
* set.
*/
public int find(final int a) {
return findNode(a).value;
}
/**
* Finds the set containing a given Node.
*/
private Node findNode(Node node) {
final Stack stack = new Stack();
// Find the child of the root element.
while (node.parent.child == null) {
stack.push(node);
node = node.parent;
}
// Do path compression on the way back down.
final Node rootChild = node;
while (!stack.empty()) {
node = (Node) stack.pop();
node.parent = rootChild;
}
Assert.isTrue(rootChild.parent.child != null);
return rootChild.parent;
}
/**
* Returns true if a and b are in the same set.
*/
public boolean isEquiv(final int a, final int b) {
return findNode(a) == findNode(b);
}
/**
* Combines the set that contains a with the set that contains b.
*/
public void union(final int a, final int b) {
final Node na = findNode(a);
final Node nb = findNode(b);
if (na == nb) {
return;
}
// Link the smaller tree under the larger.
if (na.rank > nb.rank) {
// Delete nb.
nb.child.parent = na.child;
na.value = b;
} else {
// Delete na.
na.child.parent = nb.child;
nb.value = b;
if (na.rank == nb.rank) {
nb.rank++;
}
}
}
class Node {
Node parent; // The root of the tree in which this Node resides
Node child;
int value;
int rank; // This Node's height in the tree
public Node(final int v) {
value = v;
rank = 0;
}
}
}