/* * Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center * * 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 org.fhcrc.cpl.toolbox.datastructure; import java.util.Comparator; import java.util.List; import java.util.ArrayList; /** * An in-order (left child < parent < right child) binary tree implementation * * This is a Tree that only allows two children, uses a Comparator to ensure that the * left child is somehow "less than or equal to" the parent and the right child is "greater". * Keeps track of which child is left and which is right. * * Be careful with this one... I haven't overridden methods in the superclass that might * cause trouble. Also, there should be another layer of indirection here -- a BinaryTree class * that this descends from. Maybe someday, if we need it. * */ public class InOrderBinaryTree<T> extends Tree<T> { protected Comparator<T> comparator = null; public InOrderBinaryTree(Comparator<T> comparator) { this.comparator = comparator; } public void addNode(BinaryTreeNode<T> newNode) { if (getRootElement() == null) setRootElement(newNode); else { addNode((BinaryTreeNode) getRootElement(), newNode); } } /** * by convention, if comparator returns equality, stick the new node to the left * @param parentNode * @param newNode */ public void addNode(BinaryTreeNode<T> parentNode, BinaryTreeNode<T> newNode) { int result = comparator.compare(parentNode.getData(), newNode.getData()); if (result >= 0) { if (parentNode.hasLeftChild()) addNode(parentNode.getLeftChild(), newNode); else parentNode.setLeftChild(newNode); } else { if (parentNode.hasRightChild()) addNode(parentNode.getRightChild(), newNode); else parentNode.setRightChild(newNode); } } /** * Add a bunch of nodes at once. This should really be in Tree, but I didn't want to * mess with Tree * @param newNodes */ public void populateTree(List<BinaryTreeNode<T>> newNodes) { for (BinaryTreeNode<T> newNode : newNodes) addNode(newNode); } /** * Cover method for the root node * @param minValue * @param maxValue * @return */ public List<BinaryTreeNode<T>> getNodesInRange(T minValue, T maxValue) { return getNodesInRange((BinaryTreeNode<T>) getRootElement(), minValue, maxValue); } /** * Recursive. Given a parent node, return all the nodes of the subtree rooted at that * parent that fall within the range provided. * @param parent * @param minValue * @param maxValue * @return */ public List<BinaryTreeNode<T>> getNodesInRange(BinaryTreeNode<T> parent, T minValue, T maxValue) { boolean greaterThanMin = false; boolean lessThanMax = false; List<BinaryTreeNode<T>> result = new ArrayList<BinaryTreeNode<T>>(); if (comparator.compare(parent.getData(), minValue) >= 0) greaterThanMin = true; if (comparator.compare(parent.getData(), maxValue) <= 0) lessThanMax = true; if (lessThanMax && parent.hasRightChild()) result.addAll(getNodesInRange(parent.getRightChild(), minValue, maxValue)); if (greaterThanMin && parent.hasLeftChild()) result.addAll(getNodesInRange(parent.getLeftChild(), minValue, maxValue)); if (greaterThanMin && lessThanMax) result.add(parent); return result; } /** * Convenience method to look at the nodes from getNodesInRange() and spit out the * data values * @param minValue * @param maxValue * @return */ public List<T> getDataValuesInRange(T minValue, T maxValue) { List<BinaryTreeNode<T>> nodesInRange = getNodesInRange(minValue, maxValue); List<T> result = new ArrayList<T>(nodesInRange.size()); for (BinaryTreeNode<T> nodeInRange : nodesInRange) result.add(nodeInRange.getData()); return result; } }