package com.jadekler.datastructures;
import java.util.Arrays;
import java.util.Random;
import java.util.Queue;
import java.util.Stack;
import java.util.LinkedList;
/**
* This class holds items in a binary tree fashion, without balancing
*/
public class BinaryTree
{
private Node root;
class Node {
private Node left;
private Node right;
private Node parent;
private int num;
public Node(int num) {
this.num = num;
this.left = null;
this.right = null;
this.parent = null;
}
public int getNum() {
return this.num;
}
public Node getLeft() {
return this.left;
}
public Node getRight() {
return this.right;
}
public Node getParent() {
return this.parent;
}
public void setLeft(Node node) {
this.left = node;
}
public void setRight(Node node) {
this.right = node;
}
public void setParent(Node node) {
this.parent = node;
}
}
public static void main(String args[]) {
BinaryTree bt = new BinaryTree();
bt.push(10);
bt.push(6);
bt.push(4);
bt.push(5);
bt.push(7);
bt.push(8);
bt.emitTree();
}
/**
* Pushes a num into the binary tree starting at some node (usually root)
* @param num Number to push into tree
* @return void
*/
public void push(int num) {
push(getRoot(), num);
}
/**
* Pushes a num into the binary tree starting at some node (usually root)
* @param Node node Node to push down from
* @param int num Number to push into tree
* @return void
*/
public void push(Node node, int num) {
Node newNode = new Node(num);
newNode.setParent(node);
if (node == null) {
setRoot(newNode);
} else {
if (num > node.getNum()) {
if (node.getRight() != null) {
push(node.getRight(), num);
} else {
node.setRight(newNode);
}
} else {
if (node.getLeft() != null) {
push(node.getLeft(), num);
} else {
node.setLeft(newNode);
}
}
}
}
/**
* Emits the tree visually in cli
* This function is based on camluca's 4954a1ad1d9b034abbd3c23c4581324fb6b8fa57
*/
public void emitTree()
{
Stack globalStack = new Stack();
globalStack.push(getRoot());
int emptyLeaf = 32; // Just a guess at how wide this tree should be. Increase for larger trees
boolean isRowEmpty = false;
while(isRowEmpty == false) {
Stack localStack = new Stack();
isRowEmpty = true;
for(int j = 0; j<emptyLeaf; j++)
System.out.print(' ');
while(globalStack.isEmpty() == false) {
Node temp = (Node)globalStack.pop();
if(temp != null) {
this.emitNode(temp);
localStack.push(temp.getLeft());
localStack.push(temp.getRight());
if(temp.getLeft() != null || temp.getRight() != null)
isRowEmpty = false;
} else {
System.out.print("--");
localStack.push(null);
localStack.push(null);
}
for(int j = 0; j < emptyLeaf*2-2; j++)
System.out.print(' ');
}
System.out.println();
emptyLeaf /= 2;
while(localStack.isEmpty()==false)
globalStack.push( localStack.pop() );
}
}
/**
* Emits the node with system.out
* @param Node Node to emit
* @return void
*/
public void emitNode(Node node) {
System.out.print(node.getNum());
}
/**
* Returns the tree as a stack
* @return Stack Stack with entire tree in
*/
public Stack treeToStack() {
Stack stack = new Stack();
Queue queue = treeToQueue();
while (!queue.isEmpty()) {
Node node = (Node)queue.poll();
stack.push(node);
}
return stack;
}
/**
* Returns the tree as a queue
* @return Queue Queue with entire tree in
*/
public Queue treeToQueue() {
Queue tempQueue = new java.util.LinkedList();
Queue queue = new java.util.LinkedList();
tempQueue.offer(getRoot());
queue.offer(getRoot());
treeToQueue(tempQueue, queue);
return queue;
}
/**
* Returns the tree as a queue
* @param tempQueue Temporary queue that we will poll and offer from / to
* @param queue Permanent queue that we will only be offering into
* @return Queue Queue with entire tree in
*/
public void treeToQueue(Queue tempQueue, Queue queue) {
Node node = (Node)tempQueue.poll();
if (node != null && node.getRight() != null) {
tempQueue.offer(node.getRight());
queue.offer(node.getRight());
}
if (node != null && node.getLeft() != null) {
tempQueue.offer(node.getLeft());
queue.offer(node.getLeft());
}
if (!tempQueue.isEmpty()) {
treeToQueue(tempQueue, queue);
}
}
/**
* Given some node, finds its left sibling (or null if has none)
* @param Node Node for which to find right sibling
* @return Node Left sibling (or null if none)
*/
public Node getSiblingLeft(Node node) {
if (node.getParent() != null)
return node.getParent().getLeft();
else
return null;
}
/**
* Given some node, finds its right sibling (or null if has none)
* @param Node Node for which to find right sibling
* @return Node Right sibling (or null if none)
*/
public Node getSiblingRight(Node node) {
if (node.getParent() != null)
return node.getParent().getRight();
else
return null;
}
/**
* Given a node, finds remaining distance to top
* @param node Node to find depth of
* @return int Depth (e.g. distance to top)
*/
public int getDepth(Node node) {
return getDepth(node, 0);
}
/**
* Given a node and some initial depth, finds remaining distance to top
* @param node Node to find depth of
* @param depth Initial depth that further depth will be added onto
* @return int Depth (e.g. distance to top)
*/
public int getDepth(Node node, int depth) {
if (node.getParent() == null) {
return depth;
} else {
return getDepth(node.getParent(), ++depth);
}
}
/**
* Recursively searches for num in stack (depth first search)
* @param int num Number to search for
* @return Node Node in which the number resides
*/
public Node depthFirstSearch(int num) {
Stack stack = new Stack();
stack.push(getRoot());
return depthFirstSearch(stack, num);
}
/**
* Recursively searches for num in stack (depth first search)
* @param Stack stack Stack to pop and push from / to
* @param int num Number to search for
* @return Node Node in which the number resides
*/
public Node depthFirstSearch(Stack stack, int num) {
if (stack.empty())
return null;
Node node = (Node)stack.pop();
if (node != null && node.getNum() == num)
return node;
if (node != null && node.getLeft() != null)
stack.push(node.getLeft());
if (node != null && node.getRight() != null)
stack.push(node.getRight());
return depthFirstSearch(stack, num);
}
/**
* Recursively searches for num in queue (breadth first search)
* @param int num Number to search for
* @return Node node The node in which the number resides
*/
public Node breadthFirstSearch(int num) {
Queue queue = new java.util.LinkedList();
queue.offer(getRoot());
return breadthFirstSearch(queue, num);
}
/**
* Recursively searches for num in queue (breadth first search)
* @param Queue queue Queue to pop and push from / to
* @param int num Number to search for
* @return Node Node in which the number resides
*/
public Node breadthFirstSearch(Queue queue, int num) {
if (queue.isEmpty())
return null;
Node node = (Node)queue.poll();
if (node != null && node.getNum() == num)
return node;
if (node != null && node.getRight() != null)
queue.offer(node.getRight());
if (node != null && node.getLeft() != null)
queue.offer(node.getLeft());
return breadthFirstSearch(queue, num);
}
/**
* Returns the tree as string
* @return String String format version of tree
*/
public String toString() {
return toString(getRoot());
}
/**
* Returns the tree as string
* @param Node Node from which to return all children
* @return String String format of tree
*/
public String toString(Node node) {
String str = "";
if (node == null) {
str += "Tree is empty";
} else {
if (node.getLeft() != null)
str += toString(node.getLeft());
str += Integer.toString(node.getNum())+" ";
if (node.getRight() != null)
str += toString(node.getRight());
}
return str;
}
/**
* Returns the binary tree in array format
* @return int[] Array format for tree
*/
public int[] toArray() {
return toArray(getRoot());
}
/**
* Returns the binary tree in array format
* @param Node Node from which to return all children
* @return int[] Array format of tree
*/
public int[] toArray(Node node) {
int[] arr = new int[0];
if (node == null) {
arr = new int[0];
} else {
if (node.getLeft() != null) {
int[][] leftArrs = {toArray(node.getLeft()), arr};
arr = mergeArrays(leftArrs);
}
int[] numArr = {node.getNum()};
int[][] numArrs = {arr, numArr};
arr = mergeArrays(numArrs);
if (node.getRight() != null) {
int[][] rightArrs = {arr, toArray(node.getRight())};
arr = mergeArrays(rightArrs);
}
}
return arr;
}
/**
* Merges an array of arrays into one array
* @param int[][] Arrays to merge
* @return int[] Merged array
*/
public int[] mergeArrays(int[][] arrs) {
int length = 0;
for (int i = 0; i < arrs.length; i++) {
length += arrs[i].length;
}
int[] mergedArr = new int[length];
int pointer = 0;
for (int i = 0; i < arrs.length; i++) {
System.arraycopy(arrs[i], 0, mergedArr, pointer, arrs[i].length);
pointer += arrs[i].length;
}
return mergedArr;
}
/**
* Sets the root for this binary tree
* @param node Root
* @return void
*/
public void setRoot(Node node) {
this.root = node;
}
/**
* Gets the root of this binary tree
* @return node Root node
*/
public Node getRoot() {
return this.root;
}
}