/* ************************
* Name : Eugene Krapivin *
* ID : 306255084 *
* ***********************/
package trees;
import java.util.List;
import java.io.Serializable;
import exceptions.InvalidIntervalException;
import nodes.IntervalNode;
import nodes.Node;
public class IntervalTree extends BinarySearchTree implements Serializable
{
private static final long serialVersionUID = -4862696407629432815L;
/* Constructors */
/**
* Class constructor.
* <p>
* This is a default constructor for the class. Creating a default interval
* node for the root. Using this constructor is unwise and not recommended
*
* @deprecated
*/
public IntervalTree()
{
root = new IntervalNode();
treeSetMax(root);
}
/**
* Class constructor.
* <p>
* Constructor receives 2 comparable values, creates an IntervalNode from
* them and calls an other constructor to finish the work.
*
* @param low
* The low end of the interval
* @param high
* The high end of the interval
*/
public IntervalTree(Comparable low, Comparable high)
{
this(new IntervalNode(low, high));
}
/**
* Class constructor.
* <p>
* This constructor receives an IntervalNode and uses it to initiate the
* tree. Using the the base class constructor it initiates the right and
* left nodes if available from the parameter node. The constructor it self
* initializes the low, high and max fields.
*
* @param node
* The node from which to copy the data.
*/
public IntervalTree(IntervalNode node)
{
super(node);
((IntervalNode) root).setLow(node.getLow());
((IntervalNode) root).setHigh(node.getHigh());
treeSetMax((IntervalNode) root);
}
/**
* Class copy Constructor.
* <p>
* Copy constructor receives an interval tree and copies its data to it
* self.
*
* @param intervalTree
* The tree to clone.
*/
public IntervalTree(IntervalTree intervalTree)
{
super(intervalTree);
root = intervalTree.root.clone();
treeSetMax((IntervalNode) root);
}
/* Field methods */
/**
* Setter method for root.
* <p>
* Overriding the base method setRoot to set roots that are not of Node type
* but of IntervalNode type
*
* @param root
* The root to set.
*/
@Override
public void setRoot(Node root)
{
if (root instanceof IntervalNode)
{
this.root = (IntervalNode) root.clone();
}
else
{
throw new ClassCastException(root.getClass()
+ " is an unsutable root for and interval tree.");
}
}
/**
* insertion method
* <p>
* Inserts a new interval to the tree.
* <p>
* If the interval is not appropriate the constructor of IntervalNode will
* throw an exception that will be caught here in the try-catch clause and
* dealt with. After creating the node it will be sent to the
* {@code insert(IntervalNode n)} method for insertion.
*
* @param low
* The low end of the interval to be inserted
* @param high
* The high end of the interval to be inserted
*/
public void insert(Comparable low, Comparable high)
{
try
{
insert(new IntervalNode(low, high));
}
catch (InvalidIntervalException ex)
{
System.out.println(ex.getMessage());
}
}
/**
* insertion method
* <p>
* This method receives an interval node, sends the node to the base class
* insert method. After insertion the method will run the treeSetMax method
* to re-set all the max values in the tree nodes.
*
* @param n
* The node to insert.
* @see #insert(Node, Node)
*/
protected void insert(IntervalNode n)
{
insert(root, n);
treeSetMax(this.root);
}
/**
* Search method for a specific point.
* <p>
* this method takes a point and a list to which the results will be
* written. The method creates a new interval that has one point [p,p] and
* send it to the appropriate search method.
*
* @param p
* Point to search.
* @param result
* The list to which the results will be written.
*/
public void search(Comparable p, List<IntervalNode> result)
{
try
{
search((IntervalNode) root, new IntervalNode(p, p), result);
}
catch (InvalidIntervalException ex)
{
System.out.println(ex.getMessage());
}
}
/**
* Search method for an interval.
* <p>
* The method receives an interval and a list to which to write the results.
* its a wrapper method that sends the parameters to the private search
* function.
*
* @param i
* The interval to search for intersections with
* @param result
* The result list to which to write the results.
*/
public void search(IntervalNode i, List<IntervalNode> result)
{
search((IntervalNode) root, i, result);
}
/**
* Search Method
* <p>
* This is the primary search method, all the other methods are wrappers for
* this one. The method receives the current root, the interval to check
* intersections with and the results list.
* <p>
* If intersections are found, the intersecting nodes will be written to the
* result list.
*
* @param root
* The current root to check intersection with
* @param i
* The interval to check intersection with
* @param result
* The result list to write intersecting intervals to
*/
private void search(IntervalNode root, IntervalNode i,
List<IntervalNode> result)
{
// Don't search nodes that don't exist
if (root == null)
return;
// If p is to the right of the rightmost point of any interval
// in this node and all children, there won't be any matches.
if (i.getLow().compareTo(root.getMax()) == 1)
return;
// Search left children
if (root.getLeft() != null)
search((IntervalNode) (root.getLeft()), i, result);
// Check this node
if (root.overlapsWith(i))
result.add(root);
// If p is to the left of the start of this interval,
// then it can't be in any child to the right.
if (i.getHigh().compareTo(root.getLow()) == 1)
{
if (root.getRight() != null)
{
search((IntervalNode) (root.getRight()), i, result);
}
}
}
/**
* Removal method
* <p>
* This is a wrapper method for the removal method of the base class. After
* calling the base class removal method the treeSetMax method will be
* called to re-set the max values of the nodes in the tree.
*
* @param value
* The value to remove
*/
public void remove(Comparable value)
{
super.remove(value);
treeSetMax(root);
}
/* management methods */
/**
* Method will traverse the tree using post order method, each node visited
* will be sent to the setMax() method.
*
* @param root
* The current root visiting
*/
private void treeSetMax(Node root)
{
if (root != null)
{
treeSetMax(root.getLeft());
treeSetMax(root.getRight());
setMax((IntervalNode) root);
}
}
/**
* The method checks the son's max values and compares them to the root max
* value, setting the maximal value between those to be the max value of the
* root.
*
* @param root
* Current root.
*/
private void setMax(IntervalNode root)
{
Comparable max = root.getHigh();
if (root.getLeft() != null)
{
if (((IntervalNode) root.getLeft()).getMax().compareTo(max) == 1)
{
max = ((IntervalNode) root.getLeft()).getMax();
}
}
if (root.getRight() != null)
{
if (((IntervalNode) root.getRight()).getMax().compareTo(max) == 1)
{
max = ((IntervalNode) root.getRight()).getMax();
}
}
root.setMax(max);
}
/**
* Method checks equality between trees using their toString() methods.
*
* @param t
* The tree to compare to.
* @return True if trees are the same, false otherwise.
*/
public boolean equals(IntervalTree t)
{
return this.toString().equals(t.toString());
}
/**
* method returns a string representing the tree and its nodes.
*/
public String toString()
{
return super.toString();
}
}