
dcutils.BinaryTree Maven / Gradle / Ivy
package dcutils;
// Import JDK Classes
import java.util.BitSet;
/**
* A binary tree which sorts its children based on a comparable implementation.
* E.g.:
*
* BinaryTree<Integer> tree = new BinaryTree<>();
* tree.add(55);
* tree.add(151);
* tree.add(12);
* tree.add(99);
* tree.add(200);
* tree.add(77);
* tree.add(101);
*
* The above code produces a tree which looks like this:
*
* 55
* / \
* 12 151
* / \
* 99 200
* / \
* 77 101
*
* This tree's height is 4, it's size is 7, and toString produces: [12, 55, 77, 99, 101, 151, 200]
* @author dca
*/
public class BinaryTree> {
@SuppressWarnings("unused")
private class Node {
private T data;
private Node parent;
private Node left;
private Node right;
public Node(T data, Node parent) {
this.data = data;
this.parent = parent;
this.left = null;
this.right = null;
} // END constructor
public boolean hasParent() {
return null != this.parent;
} // END hasParent
public boolean hasLeft() {
return null != this.left;
} // END hasLeft
public boolean hasRight() {
return null != this.right;
} // END hasRight
public T getData() {
return this.data;
} // END getData
public Node getParent() {
return this.parent;
} // END getParent
public Node getLeft() {
return this.left;
} // END getLeft
public Node getRight() {
return this.right;
} // END getRight
public void setData(T data) {
this.data = data;
} // END setData
public void setParent(Node parent) {
this.parent = parent;
} // END setParent
public void setLeft(Node left) {
this.left = left;
} // END setLeft
public void setRight(Node right) {
this.right = right;
} // ENDsetRight
} // END inner class Node
/**
* A reference to the tree's root.
*/
private Node root;
/**
* Adds the supplied data element to the tree.
* @param data The supplied data element.
*/
public void add(T data) {
if(null == root) {
this.root = new Node(data, null);
} else {
add(data, this.root);
} // END if/else
} // END add
private void add(T data, Node parent) {
if(data.compareTo(parent.getData()) < 0) {
if(null == parent.getLeft()) {
parent.setLeft(new Node(data, parent));
} else {
add(data, parent.getLeft());
} // END if/else
} else {
if(null == parent.getRight()) {
parent.setRight(new Node(data, parent));
} else {
add(data, parent.getRight());
} // END if/else
} // END if/else
} // END add
/**
* Removes all elements from the tree.
*/
public void clear() {
this.root = null;
System.gc();
} // END clear
/**
* Checks whether this tree contains any elements.
* @return true or false.
*/
public boolean isEmpty() {
return null == this.root;
} // END isEmpty
/**
* Returns the number of elements contained in the tree.
* @return int The number of elements.
*/
public int size() {
return size(this.root);
} // END size
private int size(Node curr) {
int size = 0;
if(null != curr) {
size++;
if(null != curr.getLeft()) {
size += size(curr.getLeft());
} // END if
if(null != curr.getRight()) {
size += size(curr.getRight());
} // END if
} // END if
return size;
} // END size
/**
* Returns how far the farthest node from the root is.
* @return int The number of paths to the farthest node.
*/
public int height() {
return height(this.root);
} // END height
private int height(Node curr) {
int height = 0;
if(null != curr) {
height++;
int left = 0;
int right = 0;
if(null != curr.getLeft()) {
left = height(curr.getLeft());
} // END if
if(null != curr.getRight()) {
right = height(curr.getRight());
} // END if
height += Math.max(left, right);
} // END if
return height;
} // END height
/**
* Checks whether the supplied data elements is contained within the tree.
* @param item The supplied data element.
* @return true or false.
*/
public boolean contains(T item) {
return contains(item, this.root);
} // END contains
private boolean contains(T item, Node curr) {
if(null != curr) {
if(item.equals(curr.getData())) {
return true;
} else {
boolean left = false;
boolean right = false;
if(null != curr.getLeft()) {
left = contains(item, curr.getLeft());
} // END if
if(null != curr.getRight()) {
right = contains(item, curr.getRight());
} // END if
return left || right;
} // END if/else
} else {
return false;
} // END if/else
} // END contains
/**
* Returns a BitSet specifying the pathways one would walk, starting from the root, in order to reach the supplied item.
* A bit set is a collection of zeros and ones.
* A zero means, follow the left child path.
* A one means, follow the right child path.
* @param item The supplied item.
* @return The bit set of pathways.
*/
public BitSet getPath(T item) {
if(contains(item)) {
String strPath = getPath(item, this.root, "");
strPath = strPath.replace("-", "");
BitSet bitPath = new BitSet(strPath.length());
for(int i = 0 ; i < strPath.length() ; ++i) {
char c = strPath.charAt(i);
if('1' == c) bitPath.set(i);
} // END loop
return bitPath;
} else {
return null;
} // END if/else
} // END getPath
private String getPath(T item, Node curr, String path) {
if(null != curr) {
if(item.equals(curr.getData())) {
return path + "-1";
} else {
if(null != curr.getLeft()) {
String left = getPath(item, curr.getLeft(), path + "0");
if(left.contains("-1")) return left;
} // END if
if(null != curr.getRight()) {
String right = getPath(item, curr.getRight(), path + "1");
if(right.contains("-1")) return right;
} // END if
} // END if/else
} // END if
return path;
} // END getPath
/**
* Returns an item from the tree by following the path of the supplied bit set.
* @param path The supplied bit set.
* @return The item found at the path of the pathway of the bit set.
*/
public T getItem(BitSet path) {
return getItem(path, this.root, 0);
} // END getItem
private T getItem(BitSet path, Node curr, int bitIndex) {
if(path.get(bitIndex)) { // path[bitIndex] == 1
if(-1 == path.nextSetBit(bitIndex + 1)) { // There are no more 1's following this
return curr.getData();
} else { // There are more 1's following this
return getItem(path, curr.getRight(), bitIndex + 1);
} // END if/else
} else { // path[bitIndex] == 0
return getItem(path, curr.getLeft(), bitIndex + 1);
} // END if/else
} // END getItem
/**
* Returns a string containing an array of data elements,
* ordered by an in-order tree traversal.
* @return A string of ordered data elements of the tree.
*/
public String toStringInOrder() {
return String.format("[%s]", toStringInOrder(this.root));
} // ENd toStringInOrder
private String toStringInOrder(Node curr) {
if(null != curr) {
String string = curr.getData().toString();
if(null != curr.getLeft()) {
string = String.format("%s, %s", toStringInOrder(curr.getLeft()), string);
} // END if
if(null != curr.getRight()) {
string = String.format("%s, %s", string, toStringInOrder(curr.getRight()));
} // END if
return string;
} else {
return "";
} // END if/else
} // END toStringInOrder
/**
* A string representation of this tree.
* This calls toStringInOrder.
* @return A string representation of the tree.
* @see #toStringInOrder()
*/
@Override
public String toString() {
return toStringInOrder();
} // END toString
} // END class BinaryTree
© 2015 - 2025 Weber Informatics LLC | Privacy Policy