/*
* Copyright (c) 2013, University of Toronto.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package edu.toronto.cs.xcurator.utils;
import java.util.LinkedList;
import java.util.List;
/**
* A simple representation of disjoint sets
*/
public class DisjointSet<T> {
/**
* The resource this set represents
*/
private T data;
/**
* The parent set in a union
*/
private DisjointSet<T> m_parent;
private List<DisjointSet<T>> m_children;
/**
* Heuristic used to build balanced unions
*/
private int m_rank;
/**
* The link to the distinguished member set
*/
private DisjointSet<T> m_ancestor;
/**
* Set to true when the node has been processed
*/
private boolean m_black = false;
/**
* Set to true when we've inspected a black set, since the result is only
* correct just after both of the sets for u and v have been marked black
*/
private boolean m_used = false;
public DisjointSet(T data) {
this.data = data;
m_rank = 0;
m_parent = this;
m_children = new LinkedList<DisjointSet<T>>();
}
public T getData() {
return data;
}
public DisjointSet<T> getParent() {
return m_parent;
}
public void setParent(DisjointSet<T> parent) {
m_parent = parent;
parent.m_children.add(this);
parent.m_children.addAll(this.m_children);
}
public int getRank() {
return m_rank;
}
public void incrementRank() {
m_rank++;
}
public DisjointSet<T> getAncestor() {
return m_ancestor;
}
public void setAncestor(DisjointSet<T> anc) {
m_ancestor = anc;
}
public void setBlack() {
m_black = true;
}
public boolean isBlack() {
return m_black;
}
public boolean used() {
return m_used;
}
public void setUsed() {
m_used = true;
}
public List<DisjointSet<T>> getChildren() {
return m_children;
}
/**
* The find operation collapses the pointer to the root parent, which is one
* of Tarjan's standard optimisations.
*
* @return The representative of the union containing this set
*/
public DisjointSet<T> find() {
DisjointSet<T> root;
if (getParent() == this) {
// the representative of the set
root = this;
} else {
// otherwise, seek the representative of my parent and save it
root = getParent().find();
setParent(root);
}
return root;
}
/**
* The union of two sets
*
* @param y
*/
public void union(DisjointSet<T> y) {
DisjointSet<T> xRoot = find();
DisjointSet<T> yRoot = y.find();
if (xRoot.getRank() > yRoot.getRank()) {
yRoot.setParent(xRoot);
} else if (yRoot.getRank() > xRoot.getRank()) {
xRoot.setParent(yRoot);
} else if (xRoot != yRoot) {
yRoot.setParent(xRoot);
xRoot.incrementRank();
}
}
/**
* @see java.lang.Object#toString()
* @return A string representation of this set for debugging
*/
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("DisjointSet{node=");
buf.append(data);
buf.append(",anc=");
buf.append((getAncestor() == this) ? "self" : (getAncestor() == null ? "null" : getAncestor().toShortString()));
buf.append(",parent=");
buf.append((getParent() == this) ? "self" : (getParent() == null ? "null" : getParent().toShortString()));
buf.append(",rank=");
buf.append(getRank());
buf.append(m_black ? ",black" : ",white");
buf.append("}");
return buf.toString();
}
public String toShortString() {
StringBuffer buf = new StringBuffer();
buf.append("DisjointSet{node=");
buf.append(data);
buf.append(",parent=");
buf.append((getParent() == this) ? "self" : (getParent() == null ? "null" : getParent().toShortString()));
buf.append("...}");
return buf.toString();
}
}