package me.ramswaroop.common;
import static java.lang.System.out;
/**
* Created by IntelliJ IDEA.
*
* @author: ramswaroop
* @date: 4/19/15
* @time: 6:35 PM
* @see: https://www.cs.bu.edu/teaching/c/tree/breadth-first/
*/
public class BinaryTree<E extends Comparable<E>> extends Tree<E> {
public BinaryNode<E> root;
Queue<BinaryNode<E>> queue = new LinkedQueue<>(); // needed for insertion
/**
* Inserts a node into the binary tree such that
* it always forms a complete binary tree.
*
* @param value
*/
public BinaryNode<E> put(E value) {
return put(root, value);
}
public BinaryNode<E> put(BinaryNode<E> node, E value) {
// create a new node from the value
BinaryNode<E> newNode = new BinaryNode<>(value, null, null);
if (node == null) {
return root = queue.add(newNode);
} else {
BinaryNode<E> parentNode = queue.element();
if (parentNode.left == null) {
parentNode.left = newNode;
} else if (parentNode.right == null) {
parentNode.right = newNode;
queue.remove(); // parent node has both left and right child now, so dequeue it
}
queue.add(newNode);
}
return node;
}
/**
* Traversals.
*/
/**
* Prints the pre-order traversal of the tree.
*/
public void preOrder() {
preOrder(root);
}
public void preOrder(BinaryNode<E> node) {
if (node == null) {
return;
}
out.print(node.value);
preOrder(node.left);
preOrder(node.right);
}
/**
* Prints the in-order traversal of the tree.
*/
public void inOrder() {
inOrder(root);
}
public void inOrder(BinaryNode<E> node) {
if (node == null) {
return;
}
inOrder(node.left);
out.print(node.value);
inOrder(node.right);
}
/**
* Prints the post-order traversal of the tree.
*/
public void postOrder() {
postOrder(root);
}
public void postOrder(BinaryNode<E> node) {
if (node == null) {
return;
}
postOrder(node.left);
postOrder(node.right);
out.print(node.value);
}
/**
* Prints the node of the tree breadth-wise.
* <p/>
* DEF: Breadth-first search (BFS) is an algorithm for traversing or searching tree
* or graph data structures. It starts at the tree root (or some arbitrary node of a
* graph, sometimes referred to as a `search key'[1]) and explores the neighbor nodes
* first, before moving to the next level neighbors. See {@link me.ramswaroop.trees.BFSUsingQueue}
* for a O(n) solution.
*
* Time complexity: O(n^2)
*/
public void breadthFirstTraversal() {
// assuming level starts at zero
for (int level = 0; level < height(root); level++) {
printLevel(root, level);
}
}
public void printLevel(BinaryNode<E> node, int level) {
if (node == null) return;
// print the starting node
if (level == 0) {
printValue(node);
} else { // print the neighbour nodes
printLevel(node.left, level - 1);
printLevel(node.right, level - 1);
}
}
/**
* Deletes the entire tree.
*/
public void delete() {
root = null;
}
/**
* Deletes a particular node from the tree
* and rearranges the remaining nodes.
*
* @param value
*/
public void delete(E value) {
}
/**
* Deletes all child nodes of {@param node}.
*
* @param node
*/
public void deleteChildren(BinaryNode<E> node) {
if (node == null) {
return;
}
node.left = null;
node.right = null;
}
/**
* Return the height of the tree.
*
* @return
*/
public int height() {
return height(root);
}
public int height(BinaryNode<E> node) {
if (node == null) return 0;
return Math.max(height(node.left), height(node.right)) + 1;
}
/**
* Returns the number of nodes currently in the tree.
*
* @return
*/
public int size() {
return size(root);
}
public int size(BinaryNode<E> node) {
if (node == null) {
return 0;
} else {
return size(node.left) + 1 + size(node.right);
}
}
/**
* Tests if this tree is empty.
*
* @return
*/
public boolean isEmpty() {
return root == null;
}
/**
* The diameter of a tree (sometimes called the width) is the number
* of nodes on the longest path between two leaves in the tree.
*
* @return the diameter of the tree.
*/
public int diameter() {
return diameter(root);
}
public int diameter(BinaryNode<E> node) {
if (node == null) return 0;
// diameter of current node
int diameter = height(node.left) + height(node.right) + 1;
// return max diameters of current node, left sub-tree and right sub-tree
return Math.max(diameter, Math.max(diameter(node.left), diameter(node.right)));
}
/**
* Width is the number of nodes in a particular level.
*
* @return maximum width of the tree.
*/
public int width() {
return width(root, 0);
}
public int width(BinaryNode<E> node, int width) {
if (node == null) return 0;
if (node.left == null && node.right == null) return 1; // for single/leaf node
int levelWidth = width(node.left, width) + width(node.right, width);
// to find max width
if (levelWidth > width) width = levelWidth;
return width;
}
public void printValue(BinaryNode<E> node) {
if (node == null) return;
out.print(node.value);
}
// test cases
public static void main(String[] a) {
BinaryTree<Integer> bt = new BinaryTree<>();
bt.put(1);
bt.put(2);
bt.put(3);
bt.put(4);
bt.put(5);
bt.put(6);
bt.put(7);
bt.put(8);
bt.breadthFirstTraversal();
out.println();
bt.inOrder();
}
}