I'm trying to construct this binary search tree in Java:
Here's my linked binary search tree implementation class:
/**
* LinkedBinarySearchTree implements the BinarySearchTreeADT interface
* with links.
*
* #author Java Foundations
* #version 4.0
*/
public class LinkedBinarySearchTree<T> extends LinkedBinaryTree<T>
implements BinarySearchTreeADT<T>
{
/**
* Creates an empty binary search tree.
*/
public LinkedBinarySearchTree()
{
super();
}
/**
* Creates a binary search with the specified element as its root.
*
* #param element the element that will be the root of the new binary
* search tree
*/
public LinkedBinarySearchTree(T element)
{
super(element);
if (!(element instanceof Comparable))
throw new NonComparableElementException("LinkedBinarySearchTree");
}
/**
* Adds the specified object to the binary search tree in the
* appropriate position according to its natural order. Note that
* equal elements are added to the right.
*
* #param element the element to be added to the binary search tree
*/
public void addElement(T element)
{
if (!(element instanceof Comparable))
throw new NonComparableElementException("LinkedBinarySearchTree");
Comparable<T> comparableElement = (Comparable<T>)element;
if (isEmpty())
root = new BinaryTreeNode<T>(element);
else
{
if (comparableElement.compareTo(root.getElement()) < 0)
{
if (root.getLeft() == null)
this.getRootNode().setLeft(new BinaryTreeNode<T>(element));
else
addElement(element, root.getLeft());
}
else
{
if (root.getRight() == null)
this.getRootNode().setRight(new BinaryTreeNode<T>(element));
else
addElement(element, root.getRight());
}
}
modCount++;
}
/**
* Adds the specified object to the binary search tree in the
* appropriate position according to its natural order. Note that
* equal elements are added to the right.
*
* #param element the element to be added to the binary search tree
*/
private void addElement(T element, BinaryTreeNode<T> node)
{
Comparable<T> comparableElement = (Comparable<T>)element;
if (comparableElement.compareTo(node.getElement()) < 0)
{
if (node.getLeft() == null)
node.setLeft(new BinaryTreeNode<T>(element));
else
addElement(element, node.getLeft());
}
else
{
if (node.getRight() == null)
node.setRight(new BinaryTreeNode<T>(element));
else
addElement(element, node.getRight());
}
}
/**
* Removes the first element that matches the specified target
* element from the binary search tree and returns a reference to
* it. Throws a ElementNotFoundException if the specified target
* element is not found in the binary search tree.
*
* #param targetElement the element being sought in the binary search tree
* #throws ElementNotFoundException if the target element is not found
*/
public T removeElement(T targetElement)
throws ElementNotFoundException
{
T result = null;
if (isEmpty())
throw new ElementNotFoundException("LinkedBinarySearchTree");
else
{
BinaryTreeNode<T> parent = null;
if (((Comparable<T>)targetElement).equals(root.element))
{
result = root.element;
BinaryTreeNode<T> temp = replacement(root);
if (temp == null)
root = null;
else
{
root.element = temp.element;
root.setRight(temp.right);
root.setLeft(temp.left);
}
modCount--;
}
else
{
parent = root;
if (((Comparable)targetElement).compareTo(root.element) < 0)
result = removeElement(targetElement, root.getLeft(), parent);
else
result = removeElement(targetElement, root.getRight(), parent);
}
}
return result;
}
/**
* Removes the first element that matches the specified target
* element from the binary search tree and returns a reference to
* it. Throws a ElementNotFoundException if the specified target
* element is not found in the binary search tree.
*
* #param targetElement the element being sought in the binary search tree
* #param node the node from which to search
* #param parent the parent of the node from which to search
* #throws ElementNotFoundException if the target element is not found
*/
private T removeElement(T targetElement, BinaryTreeNode<T> node, BinaryTreeNode<T> parent)
throws ElementNotFoundException
{
T result = null;
if (node == null)
throw new ElementNotFoundException("LinkedBinarySearchTree");
else
{
if (((Comparable<T>)targetElement).equals(node.element))
{
result = node.element;
BinaryTreeNode<T> temp = replacement(node);
if (parent.right == node)
parent.right = temp;
else
parent.left = temp;
modCount--;
}
else
{
parent = node;
if (((Comparable)targetElement).compareTo(node.element) < 0)
result = removeElement(targetElement, node.getLeft(), parent);
else
result = removeElement(targetElement, node.getRight(), parent);
}
}
return result;
}
/**
* Returns a reference to a node that will replace the one
* specified for removal. In the case where the removed node has
* two children, the inorder successor is used as its replacement.
*
* #param node the node to be removed
* #return a reference to the replacing node
*/
private BinaryTreeNode<T> replacement(BinaryTreeNode<T> node)
{
BinaryTreeNode<T> result = null;
if ((node.left == null) && (node.right == null))
result = null;
else if ((node.left != null) && (node.right == null))
result = node.left;
else if ((node.left == null) && (node.right != null))
result = node.right;
else
{
BinaryTreeNode<T> current = node.right;
BinaryTreeNode<T> parent = node;
while (current.left != null)
{
parent = current;
current = current.left;
}
current.left = node.left;
if (node.right != current)
{
parent.left = current.right;
current.right = node.right;
}
result = current;
}
return result;
}
/**
* Removes elements that match the specified target element from
* the binary search tree. Throws a ElementNotFoundException if
* the specified target element is not found in this tree.
*
* #param targetElement the element being sought in the binary search tree
* #throws ElementNotFoundException if the target element is not found
*/
public void removeAllOccurrences(T targetElement)
throws ElementNotFoundException
{
removeElement(targetElement);
try
{
while (contains((T)targetElement))
removeElement(targetElement);
}
catch (Exception ElementNotFoundException)
{
}
}
/**
* Removes the node with the least value from the binary search
* tree and returns a reference to its element. Throws an
* EmptyCollectionException if this tree is empty.
*
* #return a reference to the node with the least value
* #throws EmptyCollectionException if the tree is empty
*/
public T removeMin() throws EmptyCollectionException
{
T result = null;
if (isEmpty())
throw new EmptyCollectionException("LinkedBinarySearchTree");
else
{
if (root.left == null)
{
result = root.element;
root = root.right;
}
else
{
BinaryTreeNode<T> parent = root;
BinaryTreeNode<T> current = root.left;
while (current.left != null)
{
parent = current;
current = current.left;
}
result = current.element;
parent.left = current.right;
}
modCount--;
}
return result;
}
/**
* Removes the node with the highest value from the binary
* search tree and returns a reference to its element. Throws an
* EmptyCollectionException if this tree is empty.
*
* #return a reference to the node with the highest value
* #throws EmptyCollectionException if the tree is empty
*/
public T removeMax() throws EmptyCollectionException
{
T result = null;
if (isEmpty())
throw new EmptyCollectionException ("binary tree");
else
{
if (root.right == null)
{
result = root.element;
root = root.left;
} //if
else
{
BinaryTreeNode<T> parent = root;
BinaryTreeNode<T> current = root.right;
while (current.right != null)
{
parent = current;
current = current.right;
} //while
result = current.element;
parent.right = current.left;
} //else
modCount--;
} //else
return result;
}
/**
* Returns the element with the least value in the binary search
* tree. It does not remove the node from the binary search tree.
* Throws an EmptyCollectionException if this tree is empty.
*
* #return the element with the least value
* #throws EmptyCollectionException if the tree is empty
*/
public T findMin() throws EmptyCollectionException
{
T result = null;
if (isEmpty())
throw new EmptyCollectionException ("binary tree");
else
{
BinaryTreeNode<T> current = root;
while (current.left != null)
current = current.left;
result = current.element;
} //else
return result;
}
/**
* Returns the element with the highest value in the binary
* search tree. It does not remove the node from the binary
* search tree. Throws an EmptyCollectionException if this
* tree is empty.
*
* #return the element with the highest value
* #throws EmptyCollectionException if the tree is empty
*/
public T findMax() throws EmptyCollectionException
{
T result = null;
if (isEmpty())
throw new EmptyCollectionException ("binary tree");
else
{
BinaryTreeNode<T> current = root;
while (current.right != null)
current = current.right;
result = current.element;
} //else
return result;
}
/**
* Returns a reference to the specified target element if it is
* found in the binary tree. Throws a NoSuchElementException if
* the specified target element is not found in this tree.
*
* #param targetElement the element being sought in the binary tree
* #throws ElementNotFoundException if the target element is not found
*/
public T find(T targetElement) throws ElementNotFoundException
{
BinaryTreeNode<T> current = root;
BinaryTreeNode<T> temp = current;
if (!(current.element.equals(targetElement)) && (current.left !=null)&&(((Comparable)current.element).compareTo(targetElement) > 0))
current = findNode( targetElement, current.left);
else if (!(current.element.equals(targetElement)) && (current.right != null))
current = findNode( targetElement, current.right);
if (!(current.element.equals(targetElement)))
throw new ElementNotFoundException ("binarytree");
return current.element;
}
/**
* Returns the left subtree of the root of this tree.
*
* #return a link to the left subtree of the tree
*/
public LinkedBinarySearchTree<T> getLeft()
{
if (root == null)
throw new EmptyCollectionException("getLeft failed - the tree is empty");
LinkedBinarySearchTree <T> result = new LinkedBinarySearchTree<T> ();
result.root = root.getLeft();
return result;
}
/**
* Returns the right subtree of the root of this tree.
*
* #return a link to the right subtree of the tree
*/
public LinkedBinarySearchTree<T> getRight()
{
if (root == null)
throw new EmptyCollectionException("getLeft failed - the tree is empty");
LinkedBinarySearchTree <T> result = new LinkedBinarySearchTree<T> ();
result.root = root.getRight();
return result;
}
/**
* Returns a reference to the specified target element if it is
* found in this tree.
*
* #param targetElement the element being sought in the tree
* #param next the tree node to begin searching on
*/
private BinaryTreeNode<T> findNode(T targetElement, BinaryTreeNode<T> next)
{
BinaryTreeNode<T> current = next;
if (!(next.element.equals(targetElement)) && (next.left !=null) &&(((Comparable)next.element).compareTo(targetElement) > 0))
next = findNode( targetElement, next.left);
else if (!(next.element.equals(targetElement)) && (next.right != null))
next = findNode( targetElement, next.right);
return next;
}
/*balances the binary search tree so that it maintains
* the maximum difference of the path lengths of the
* left and right children as not more than one*/
public void balance() {
//verify if balance factor of the root of the tree is -2
if(getBalanceFactor(root) == -2) {
//verify if balance factor of left child of tree root is 1
if(getBalanceFactor(root.left) == 1)
root = leftRightRotation(root);
else
root = rightRotation(root);
}
//verify if balance factor of tree root is 2
else if(getBalanceFactor(root) == 2) {
//verify if balance factor of right child of tree root is -1
if(getBalanceFactor(root.right) == -1) {
root = rightLeftRotation(root);
}
else
root = leftRotation(root);
}
}
/*performs right rotation and left rotation, then returns new root*/
private BinaryTreeNode<T> rightLeftRotation(BinaryTreeNode<T> current) {
current.right = rightRotation(current.right);
current = leftRotation(current);
return current;
}
/*performs left rotation then right rotation then returns new root*/
private BinaryTreeNode<T> leftRightRotation(BinaryTreeNode<T> current) {
current.left = leftRotation(current.left);
current = rightRotation(current);
return current;
}
/*returns new root after performing right rotation of specified node*/
private BinaryTreeNode<T> rightRotation(BinaryTreeNode<T> current) {
BinaryTreeNode<T> newRoot = current.left;
BinaryTreeNode<T> temp = newRoot.right;
newRoot.right = current;
current.left = temp;
return newRoot;
}
//returns new root after performing left rotation of specified node
private BinaryTreeNode<T> leftRotation(BinaryTreeNode<T> current) {
BinaryTreeNode<T> newRoot = current.right;
BinaryTreeNode<T> temp = newRoot.left;
newRoot.left = current;
current.right = temp;
return newRoot;
}
//returns difference between path lengths of heights of left and right sides of root
private int getBalanceFactor(BinaryTreeNode<T> current) {
int leftHeight = getHeight(current.left);
int rightHeight = getHeight(current.right);
return(rightHeight - leftHeight);
}
//returns the height of the specified node
private int getHeight(BinaryTreeNode<T> newRoot) {
if(newRoot == null)
return 0;
else
return 1 + Math.max(getHeight(newRoot.left), getHeight(newRoot.right));
}
}
Here's my driver program where my utlimate goal is to create the binary search tree from the image above, balance it, and test if it is balanced:
import java.util.*;
import java.io.*;
public class IsHeightBalanced {
public static void main(String[] args) {
LinkedBinarySearchTree<int> tree = new LinkedBinarySearchTree<int>;
tree.addElement(13);
tree.addElement(7);
tree.addElement(15);
tree.addElement(5);
tree.addElement(10);
tree.addElement(3);
}
}
Right now I'm just trying to construct that binary search tree from the picture here and the line
LinkedBinarySearchTree<int> tree = new LinkedBinarySearchTree<int>();
is giving me errors like "insert dimensions to complete reference type"
Why is this giving such an error? Am I on the right track to creating the binary search tree seen in the picture above? Thanks.
You Cannot Instantiate Generic Types with Primitive Types.
for an example
Consider the following parameterized type:
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
// ...
}
When creating a Pair object, you cannot substitute a primitive type for the type parameter K or V:
Pair<int, char> p = new Pair<>(8, 'a'); // compile-time error
You can substitute only non-primitive types for the type parameters K and V:
Pair<Integer, Character> p = new Pair<>(8, 'a');
Note that the Java compiler autoboxes 8 to Integer.valueOf(8) and 'a' to Character('a'):
Pair<Integer, Character> p = new Pair<>(Integer.valueOf(8), new Character('a'));
Related
I have to implement an add method for a BST in java, but can not get my add function to work. Could someone help me out?
private boolean add(E x, BinaryNode<E> currentNode){
if (currentNode == null){
currentNode = new BinaryNode<>(x);
size++;
return true;
}
if (currentNode.element.compareTo(x) == 0){
return false;
}
else if((currentNode.element.compareTo(x) < 0)){
if(currentNode.left == null){
currentNode.left = new BinaryNode<>(x);
size++;
return true;
} else {
add(x, currentNode.left);
}
}
else if(currentNode.element.compareTo(x) > 0){
if(currentNode.right == null){
currentNode.right = new BinaryNode<>(x);
size++;
return true;
} else {
add(x, currentNode.right);
}
}
return false;
}
public boolean add(E x){
return this.add(x, root);
}
One problem I see is that when you assign the root element you assign it to a local variable. This obviously doesn't work.
private boolean add(E x, BinaryNode<E> currentNode){
/////// REMOVE
if (currentNode == null){
currentNode = new BinaryNode<>(x);
size++;
return true;
}
///////
And add this
public boolean add(E x){
if( root == null ) {
root = new BinaryNode<>(x);
size++;
return true;
} else
return this.add(x, root);
}
Basically, the root of subtree might change, and this is a recursion, to make it work the return value should be the new root of the subtree, despite it changed or not.
Following are the add() method taken from my BST impl in Java, that with all test cases passed:
/**
* Add a new value.
*
* #param v
*/
#Override
public void add(T v) {
root = add(root, v);
}
/**
* Add to a subtree start from given node.
*
* #param current root of a subtree to add node to,
* #param v
* #return the new root of subtree,
*/
protected BSTNode<T> add(BSTNode<T> current, T v) {
if (current == null) { // subtree is empty,
size++;
return new BSTNode<>(v);
}
// compare,
int compareFlag = v.compareTo(current.value);
// check this or subtree,
if (compareFlag < 0) { // smaller, go to left subtree,
current.left = add(current.left, v);
} else if (compareFlag > 0) { // larger, go to right subtree,
current.right = add(current.right, v);
} else { // equals, ignore it,
}
return current;
}
I'm having a problem with my getHeight() method, it is not returning the correct height for the tree. I really think the problem has something to do with my QueueList Class but I can not for the life of me solve the issue. I'm open to suggestions on how to better implement a Binary search. Below is my QueueList Class.
package lab5;
import java.util.NoSuchElementException;
public class QueueList<E> implements Queue<E> {
private Node<E> front;
private Node<E> rear;
private int size = 0;
public QueueList (E it){
front = rear = new Node<E>(it);
size++;
}
public QueueList(){
front = rear = new Node<E>();
size=0;
}
public boolean isEmpty() {
return size==0;
}
public void enqueue(E it) {
rear.setNext(rear);
rear.setElement(it);
size++;
}
public void clear() {
front=new Node<E>();
rear=new Node<E>();
front.setNext(null);
rear.setNext(null);
front.setNext(null);
size=0;
}
public int size() {
return size;
}
public E front() {
return front.getElement();
}
public E dequeue() {
Node<E> temp = front;
if(isEmpty()){
throw new NoSuchElementException();
}
else{
front = front.getNext();
size--;
return temp.getElement();
}
}
}
Here is my Binary search tree class, all of my BSTNode Method works correctly so just assume that is not the issue.
package lab5;
public class BinarySearchTree<E extends Comparable<E>> {
private BSTNode root;
private int size;
public BinarySearchTree() {
root = null;
size = 0;
}
public BinarySearchTree(BSTNode node) {
root = node;
size = 1;
}
/**
* searches for a node that contains it.
*
* if it finds it, it returns that node
*
* else it returns null
*
* #param it
* - the element to look for
*
* #return the node that contains it
*
*/
public BSTNode search(E it) {
BSTNode<E> parent = null;
BSTNode<E> child = null;
BSTNode<E> node = root;
while (node != null && node.getElement() != it) {
parent = node;
int compareResult = it.compareTo(node.getElement());
if (compareResult < 0) {
node = node.getLeft();
} else {
node = node.getRight();
}
}
if (node == null) {
return null;
}
return node;
}
/**
* determines if the tree contains the element
*
* #return true if it is in the tree
*
*/
public boolean contains(E it) {
return (search(it) != null);
}
/**
* Add the element to the correct location
*
* all elements to the left are less than the parent
*
* all elements to the rights are greater than the parent
*
* Do not allow duplicates
*
* #param it
* the element to insert
*
*/
public void insert(E it) {
BSTNode<E> newNode = new BSTNode<E>(it);
if (root == null) {
root = newNode;
return;
}
BSTNode<E> parent = null;
BSTNode<E> node = root;
while (node != null) {
parent = node;
int compareResult = it.compareTo(node.getElement());
if (compareResult < 0) {
node = node.getLeft();
} else if (compareResult > 0) {
node = node.getRight();
} else {
// duplicate
return;
}
}
int res = it.compareTo(parent.getElement());
if (res < 0) {
parent.setLeft(newNode);
} else {
parent.setRight(newNode);
}
size++;
}
/**
* Removes the node that contains it.
*
* If the tree does not contain it, it prints that to
*
* the user and does nothing else.
*
* Otherwise it removes the node and maintains the
*
* BST properties
*
* if removing a node with two children, replace it
*
* with its in order predecessor.
*
* #param the
* element of the node you want to remove.
*
*/
public void remove(E it) {
BSTNode<E> parent = null;
BSTNode<E> child = null;
BSTNode<E> node = root;
// Find the node that contains it
while (node != null && node.getElement() != it) {
parent = node;
int compareResult = it.compareTo(node.getElement());
if (compareResult < 0) {
node = node.getLeft();
} else {
node = node.getRight();
}
}
if (node == null) {
System.out.println("failed to find: " + it + " for removal");
return;
}
if (node.isLeaf()) {
if (parent == null) {
root = null;
} else if (it.compareTo(parent.getElement()) < 0) {
parent.setLeft(null);
} else {
parent.setRight(null);
}
} else if (node.getLeft() == null) {
child = node.getRight();
swapElements(node, child);
node.setLeft(child.getLeft());
node.setRight(child.getRight());
} else if (node.getRight() == null) {
child = node.getLeft();
} else {
child = node.getLeft();
parent = null;
while (child.getRight() != null) {
parent = child;
child = parent.getRight();
}
if (parent == null) {
swapElements(node, child);
node.setLeft(child.getLeft());
} else {
swapElements(node, child);
parent.setRight(child.getLeft());
}
}
size--;
}
/**
* Returns the height of the tree
*
* if tree is empty, height is -1
*
* if tree only has one node, height is 0
*
* #return the integer height of the tree
*
*
*
*/
public int getHeight() {
int height = -1;
QueueList<BSTNode> q = new QueueList<BSTNode>();
if (root == null) {
return height;
}
q.enqueue(root);
while (!q.isEmpty()) {
int nodeCount = q.size();
height++;
while (nodeCount > 0) {
BSTNode<E> node = q.dequeue();
if (node.hasLeft()) {
q.enqueue(node.getLeft());
}
if (node.hasRight()) {
q.enqueue(node.getRight());
}
nodeCount--;
}
}
return height;
}
/**
* Helper method
*
* For removal you need to swap elements of nodes
*
* #param node1
* , node2 the nodes whose contents you are swapping
*
*/
private void swapElements(BSTNode node1, BSTNode node2) {
BSTNode temp = null;
temp.setElement(node1.getElement());
node1.setElement(node2.getElement());
node2.setElement(temp.getElement());
}
/**
* prints each level of the tree on its own line
*
* use your Queue class
*
*/
public void printLevelOrder() {
QueueList<BSTNode> q = new QueueList<BSTNode>();
q.enqueue(root);//You don't need to write the root here, it will be written in the loop
while (q.size() > 0)
{
BSTNode n = q.dequeue();
System.out.println(n.toString()); //Only write the value when you dequeue it
if (n.hasLeft())
{
q.enqueue(n.getLeft());//enqueue the left child
}
if (n.hasRight())
{
q.enqueue(n.getRight());//enque the right child
}
}
}
/**
* prints the tree in a depth-first fashion
*
* use your Stack class
*
*/
public void printByDepth() {
StackList<BSTNode> s = new StackList<BSTNode>();
s.push(root);
while (s.isEmpty() == false) {
BSTNode x = s.pop();
if (x.getRight() != null)
s.push(x.getRight());
if (x.getLeft() != null)
s.push(x.getRight());
System.out.print(" " + x.toString());
}
}
/**
* prints the tree in an inorder fashion.
*
* uses a stack to push left children onto the stack
*
*/
public void printInOrder() {
if (root == null)
return;
StackList s = new StackList();
BSTNode currentNode = root;
while (!s.isEmpty() || currentNode != null) {
if (currentNode != null) {
s.push(currentNode);
currentNode = currentNode.getLeft();
} else {
BSTNode n = null;
n.setElement(s.pop());
System.out.printf("%d ", n.toString());
currentNode = n.getRight();
}
}
}
}
As recursion is very popular when dealing with binary trees, you can use this solution:
public int getHeight() {
return getHeight(root, 0);
}
private int getHeight(BSTNode node, int currentHeight) {
if (node == null) {
return currentHeight;
}
int rightHeight = getHeight(node.getRight(), currentHeight + 1)
int leftHeight = getHeight(node.getLeft(), currentHeight + 1);
return Math.max(rightHeight, leftHeight);
}
Note that it returns height=0 for an empty tree.
I cannot compile the following line in eclipse:
Iterator<T> allElementsInTree = theTree.iteratorLevelOrder();
.iteratorLevelOrder(); returns an object of type Iterator<T> yet eclipse is telling me that
T cannot be resolved to a type
as an error. Anyone understand why this is?
Edit: For some reason is runs as Iterator<String> however it crashes during runtime stating an
invalid cast error
This is the code of the method:
public Iterator<T> iteratorLevelOrder()
{
ArrayUnorderedList<T> nodes = new ArrayUnorderedList<T>();
ArrayUnorderedList<T> templist = new ArrayUnorderedList<T>();
BinaryTreeNode<T> current;
nodes.addToRear (root.element);
while (! nodes.isEmpty())
{
current = (BinaryTreeNode<T>)nodes.removeFirst();
if (current != null)
{
templist.addToRear(current.element);
nodes.addToRear (current.left.element);
nodes.addToRear (current.right.element);
}//if
else
templist.addToRear(null);
}//while
return templist.iterator();
} // method levelorder
This is the main method.
public static void main(String[] args) {
LinkedBinaryTree<String> theTree = null; //theTree built here.
TreeBuilder<String> theTreeBuilder = null;
try{
theTreeBuilder = new TreeBuilder<String>(args[0]);
theTree = theTreeBuilder.buildTree();
}
catch( MalformedTreeFileException e) {
System.out.println( e.getMessage());
}
catch( IOException e){
System.out.println("Error reading file: " + args[0] + "\n" + e.getMessage());
}
And LinkedBinaryTree:
public class LinkedBinaryTree<T> implements BinaryTreeADT<T>
{
protected int count;
protected BinaryTreeNode<T> root;
/**
* Creates an empty binary tree.
*/
public LinkedBinaryTree()
{
count = 0;
root = null;
}
/**
* Creates a binary tree with the specified element as its root.
*
* #param element the element that will become the root of the new binary
* tree
*/
public LinkedBinaryTree (T element)
{
count = 1;
root = new BinaryTreeNode<T> (element);
}
/**
* Returns a reference to the element at the root
*
* #return a reference to the specified target
* #throws EmptyCollectionException if the tree is empty
*/
public T getRoot() throws EmptyCollectionException
{
return root.element;
}
/**
* Returns true if this binary tree is empty and false otherwise.
*
* #return true if this binary tree is empty
*/
public boolean isEmpty()
{
return count==0;
}
/**
* Returns the integer size of this tree.
*
* #return the integer size of this tree
*/
public int size()
{
return count;
}
/**
* Performs an inorder traversal on this binary tree by calling an
* overloaded, recursive inorder method that starts with
* the root.
*
* #return an in order iterator over this binary tree
*/
public Iterator<T> iteratorInOrder()
{
ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>();
inorder (root, tempList);
return tempList.iterator();
}
/**
* Performs a recursive inorder traversal.
*
* #param node the node to be used as the root for this traversal
* #param tempList the temporary list for use in this traversal
*/
protected void inorder (BinaryTreeNode<T> node,
ArrayUnorderedList<T> tempList)
{
if (node != null)
{
inorder (node.left, tempList);
tempList.addToRear(node.element);
inorder (node.right, tempList);
}
}
/**
* Performs an preorder traversal on this binary tree by calling
* an overloaded, recursive preorder method that starts with
* the root.
*
* #return an pre order iterator over this tree
*/
//public Iterator<T> iteratorPreOrder()
//{
//left as programming project
//}
/**
* Performs a recursive preorder traversal.
*
* #param node the node to be used as the root for this traversal
* #param tempList the temporary list for use in this traversal
*/
protected void preorder (BinaryTreeNode<T> node, ArrayUnorderedList<T> templist)
{
if (node != null)
{
templist.addToRear(node.element);
preorder (node.left, templist);
preorder (node.right, templist);
}//if
} // method preorder
/**
* Performs an postorder traversal on this binary tree by calling
* an overloaded, recursive postorder method that starts
* with the root.
*
* #return a post order iterator over this tree
*/
public Iterator<T> iteratorPreOrder()
{
ArrayUnorderedList<T> templist = new ArrayUnorderedList<T>();
preorder (root, templist);
return templist.iterator();
} // method preorder
public Iterator<T> iteratorPostOrder()
{
ArrayUnorderedList<T> templist = new ArrayUnorderedList<T>();
postorder (root, templist);
return templist.iterator();
} // method postorder
/**
* Performs a recursive postorder traversal.
*
* #param node the node to be used as the root for this traversal
* #param tempList the temporary list for use in this traversal
*/
protected void postorder (BinaryTreeNode<T> node, ArrayUnorderedList<T> templist)
{
if (node != null)
{
postorder (node.left, templist);
postorder (node.right, templist);
templist.addToRear(node.element);
}//if
} // method postorder
/**
* Performs a levelorder traversal on this binary tree, using a
* templist.
*
* #return a levelorder iterator over this binary tree
*/
public Iterator<T> iteratorLevelOrder()
{
ArrayUnorderedList<T> nodes = new ArrayUnorderedList<T>();
ArrayUnorderedList<T> templist = new ArrayUnorderedList<T>();
BinaryTreeNode<T> current;
nodes.addToRear (root.element);
while (! nodes.isEmpty())
{
current = (BinaryTreeNode<T>)nodes.removeFirst();
if (current != null)
{
templist.addToRear(current.element);
nodes.addToRear (current.left.element);
nodes.addToRear (current.right.element);
}//if
else
templist.addToRear(null);
}//while
return templist.iterator();
} // method levelorder
Iterator allElementsInTree = theTree.iteratorLevelOrder();
Use the type(Integer, String or CustomObject) you have supplied to create theTree class.
Iterator<Integer> allElementsInTree = theTree.iteratorLevelOrder();
Or
Iterator<BinaryTreeDataModel> allElementsInTree = theTree.iteratorLevelOrder();
I've been trying to write a recursive string method for a binary search tree that returns a multiple line representation of a tree with preorder path info.
Each node should be prefaced by a series of < and > characters showing the path that leads from the root to that node. I'm not sure how to use a string prefix parameter that is extended by one character with each successive call.
The method should be able reproduce this example:
Tree:
15
/ \
12 18
/ / \
10 16 20
\ \
11 17
Expected Print Output:
15
<12
<<10
<<>11
>18
><16
><>17
>>20
I'm new to recursion and so far my actual print output isn't close enough after hours of messing with the code:
18
<17
<10
>15
<11
>12
16
20
Here's my tree node class that works properly:
/**
* A single binary tree node.
* <p>
* Each node has both a left or right child, which can be null.
*/
public class TreeNode<E> {
private E data;
private TreeNode<E> left;
private TreeNode<E> right;
/**
* Constructs a new node with the given data and references to the
* given left and right nodes.
*/
public TreeNode(E data, TreeNode<E> left, TreeNode<E> right) {
this.data = data;
this.left = left;
this.right = right;
}
/**
* Constructs a new node containing the given data.
* Its left and right references will be set to null.
*/
public TreeNode(E data) {
this(data, null, null);
}
/** Returns the item currently stored in this node. */
public E getData() {
return data;
}
/** Overwrites the item stored in this Node with the given data item. */
public void setData(E data) {
this.data = data;
}
/**
* Returns this Node's left child.
* If there is no left left, returns null.
*/
public TreeNode<E> getLeft() {
return left;
}
/** Causes this Node to point to the given left child Node. */
public void setLeft(TreeNode<E> left) {
this.left = left;
}
/**
* Returns this nodes right child.
* If there is no right child, returns null.
*/
public TreeNode<E> getRight() {
return right;
}
/** Causes this Node to point to the given right child Node. */
public void setRight(TreeNode<E> right) {
this.right = right;
}
}
Here's my binary search tree class with the toFullString() method near the bottom:
import java.util.*;
/**
* A binary search tree (BST) is a sorted ADT that uses a binary
* tree to keep all elements in sorted order. If the tree is
* balanced, performance is very good: O(n lg n) for most operations.
* If unbalanced, it performs more like a linked list: O(n).
*/
public class BinarySearchTree<E extends Comparable<E>> {
private TreeNode<E> root = null;
private int size = 0;
/** Creates an empty tree. */
public BinarySearchTree() {
}
public BinarySearchTree(Collection<E> col) {
List<E> list = new ArrayList<E>(col);
Collections.shuffle(list);
for (int i = 0; i < list.size() ; i++) {
add(list.get(i));
}
}
/** Adds the given item to this BST. */
public void add(E item) {
this.size++;
if (this.root == null) {
//tree is empty, so just add item
this.root = new TreeNode<E>(item);
}else {
//find where to insert, with pointer to parent node
TreeNode<E> parent = null;
TreeNode<E> curr = this.root;
boolean wentLeft = true;
while (curr != null) { //will execute at least once
parent = curr;
if (item.compareTo(curr.getData()) <= 0) {
curr = curr.getLeft();
wentLeft = true;
}else {
curr = curr.getRight();
wentLeft = false;
}
}
//now add new node on appropriate side of parent
curr = new TreeNode<E>(item);
if (wentLeft) {
parent.setLeft(curr);
}else {
parent.setRight(curr);
}
}
}
/** Returns the greatest (earliest right-most node) of the given tree. */
private E findMax(TreeNode<E> n) {
if (n == null) {
return null;
}else if (n.getRight() == null) {
//can't go right any more, so this is max value
return n.getData();
}else {
return findMax(n.getRight());
}
}
/**
* Returns item from tree that is equivalent (according to compareTo)
* to the given item. If item is not in tree, returns null.
*/
public E get(E item) {
return get(item, this.root);
}
/** Finds it in the subtree rooted at the given node. */
private E get(E item, TreeNode<E> node) {
if (node == null) {
return null;
}else if (item.compareTo(node.getData()) < 0) {
return get(item, node.getLeft());
}else if (item.compareTo(node.getData()) > 0) {
return get(item, node.getRight());
}else {
//found it!
return node.getData();
}
}
/**
* Removes the first equivalent item found in the tree.
* If item does not exist to be removed, throws IllegalArgumentException().
*/
public void remove(E item) {
this.root = remove(item, this.root);
}
private TreeNode<E> remove(E item, TreeNode<E> node) {
if (node == null) {
//didn't find item
throw new IllegalArgumentException(item + " not found in tree.");
}else if (item.compareTo(node.getData()) < 0) {
//go to left, saving resulting changes made to left tree
node.setLeft(remove(item, node.getLeft()));
return node;
}else if (item.compareTo(node.getData()) > 0) {
//go to right, saving any resulting changes
node.setRight(remove(item, node.getRight()));
return node;
}else {
//found node to be removed!
if (node.getLeft() == null && node.getRight() == null) {
//leaf node
return null;
}else if (node.getRight() == null) {
//has only a left child
return node.getLeft();
}else if (node.getLeft() == null) {
//has only a right child
return node.getRight();
}else {
//two children, so replace the contents of this node with max of left tree
E max = findMax(node.getLeft()); //get max value
node.setLeft(remove(max, node.getLeft())); //and remove its node from tree
node.setData(max);
return node;
}
}
}
/** Returns the number of elements currently in this BST. */
public int size() {
return this.size;
}
/**
* Returns a single-line representation of this BST's contents.
* Specifically, this is a comma-separated list of all elements in their
* natural Comparable ordering. The list is surrounded by [] characters.
*/
#Override
public String toString() {
return "[" + toString(this.root) + "]";
}
private String toString(TreeNode<E> n) {
//would have been simpler to use Iterator... but not implemented yet.
if (n == null) {
return "";
}else {
String str = "";
str += toString(n.getLeft());
if (!str.isEmpty()) {
str += ", ";
}
str += n.getData();
if (n.getRight() != null) {
str += ", ";
str += toString(n.getRight());
}
return str;
}
}
public String toFullString() {
StringBuilder sb = new StringBuilder();
toFullString(root, sb);
return sb.toString();
}
/**
* Preorder traversal of the tree that builds a string representation
* in the given StringBuilder.
* #param n root of subtree to be traversed
* #param sb StringBuilder in which to create a string representation
*/
private void toFullString(TreeNode<E> n, StringBuilder sb)
{
if (n == null)
{
return;
}
sb.append(n.getData().toString());
sb.append("\n");
if (n.getLeft() != null) {
sb.append("<");
} else if (n.getRight() != null) {
sb.append(">");
}
if (n.getLeft() != null || n.getRight() != null)
{
toFullString(n.getLeft(), sb);
toFullString(n.getRight(), sb);
}
}
/**
* Tests the BST.
*/
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add(15);
collection.add(12);
collection.add(18);
collection.add(10);
collection.add(16);
collection.add(20);
collection.add(11);
collection.add(17);
BinarySearchTree bst = new BinarySearchTree(collection);
//System.out.println(bst);
String temp = bst.toFullString();
System.out.println(temp);
}
}
Any help with the recursive toFullString method will be greatly appreciated.
There are two levels you need to think about when designing a recursive solution.
How do I deal with the current item in the recursion?
How do I go from this item to the next one, and what information gets passed on?
Since we are printing out each item in the tree, there is going to be a single print statement inside of each recursive call. However, the string printed in each row includes information about previous steps that were traversed to reach the current node. How do we deal with this information? It needs to be passed down from previous recursive calls to the next one.
Here is a set of possible rules:
If the current item is a leaf, print out the current result.
If the current item has a left node, add <, and recursively act on the left node.
If the current item has a right node, add >, and recursively act on the right node.
What do we add < and > to? We need a parameter to carry along the current previous steps that have occurred in the recursion from recursive call to call. You don't want to simply print out < and > as you traverse the tree, because you need to remember the current set of steps to print out the prefix to every single node. There could be a second helper method that takes the same parameters as the original toFullString(), but a custom third parameter to carry the current set of previous steps.
So the logic might look something like this:
If there is no current prefix, initialize prefix to "", since the root initially has no steps to reach it.
If the current node is a leaf, add a line of output with the current prefix + leaf value.
If the current node has a left node, recursively call toFullString() on the left node, and add < to the current prefix string, which is handed down.
If the current node has a right node, recursively call toFullString() on the right node, and add > to the current prefix string, which is handed down.
I am trying to implement a Linked List Sequence in Java however my method for inserting an object at the start of the sequence inserts the object twice and I don't understand why.
If anyone can help it would be really appreciated.
The current output of my test program is
30
30
but I want it to be 30
Thanks in advance
Below is the code for the sequence and the method for insertFirst
public class Sequence implements SequenceInterface{
private Node listHead;
private Node listTail;
protected class Node{
protected Object datum;
protected Node next;
public Node(Object o, Node n) {
datum = o;
next = n;
}
}
//Constructor
public Sequence(){
listHead = null;
listTail = null;
}
public void insertFirst(Object o) {
if(listHead == null){
listHead = new Node(o, listTail);
listTail = listHead;
}else{
Node oldLH = listHead;
listHead = new Node(o, oldLH);
}
}
}
Here is my test program
public class SequenceTest {
/**
* #param args
* #throws Exception
*/
public static void main(String[] args) throws Exception {
Sequence s = new Sequence();
s.insertFirst(new Integer(30));
for(int i=0; i<2; i++){
System.out.println(s.element(i));
}
}
}
It looks like it is only added once, but is being printed twice.
If you unroll the loop:
for(int i=0; i<2; i++){
System.out.println(s.element(i));
}
you essentially get:
System.out.println(s.element(0));
System.out.println(s.element(1));
so if this is unexpected behaviour, what we really need to look at to diagnose it is the element() method.
What do you want to happen when s.element(2) is called and 's' only contains one element? Should it throw an index out of range exception? Should it wrap or crop to within range when it is indexed past the lists range (presumably the current behaviour)?
Assuming you are trying to create a singly linked list, you've got this backwards:
listHead = new Node(o, listTail);
listTail = listHead;
When you execute that, you are assigning the new node to both listHead and listTail. You should have
listTail = listHead;
listHead = new Node(o, listTail);
public void insertFirst(Object o) {
Node newNode = new Node(o, listHead);
if (listHead == null) {
listHead = newNode;
listTail = listHead;
} else {
listHead = newNode;
}
}
This is the final version tested that works perfectly! Hope this helps:
class SequenceDLListException extends Exception {
SequenceDLListException() {
super();
}
SequenceDLListException(String s) {
super(s);
}
}
/**
* <dl>
* <dt>Purpose: Implementation of Sequence ADT.
* <dd>
*
* <dt>Description:
* <dd>This class is an implementation of the Sequence using an linked list as
* the underlying data structure. The capacity is therefore unlimited and
* overflow does not need to be checked.
* </dl>
*
*
* #version $Date: 2015/01/30
*/
public class SequenceDLList {
/**
* Member class Node encapsulates the nodes of the linked list in
* which the stack is stored. Each node contains a data item and a
* reference to another node - the next in the linked list.
*
*
*/
public Node lastNode() {
return listTail;
}
public Node firstNode() {
return listHead;
}
protected class Node {
public Node(Object o) {
this(o, null, null);
}
/**
* I added another null because it has to point at the beginning and at the end
* to some kind of terminator to facilitate the traversal of the list
*/
public Node(Object o, Node p, Node n) {
datum = o;
prev =p;
next = n;
}
/**
* I added another Node because every node has two links now with the Doubly Linked List
*/
//The Node data structure consists of two object references.
//One for the datum contained in the node and the other for
//the next node in the list.
protected Object datum;
protected Node next;
protected Node prev;
}
//We use object references to the head and tail of the list (the head
//and tail of the sequence, respectively).
private Node listHead;
private Node listTail;
//Only require a single constructor, which sets both object
//references to null.
/**
* Constructs an empty sequence object.
*/
public SequenceDLList() {
listHead = null;
listTail = null;
}
/**
* Adds a new item at the start of the sequence.
*/
public void insertFirst(Object o) {
//There is a special case when the sequence is empty.
//Then the both the head and tail pointers needs to be
//initialized to reference the new node.
if (listHead == null) {
listHead = new Node(o, listHead, null);
listTail = listHead;
}
//In the general case, we simply add a new node at the start
//of the list via the head pointer.
else {
listHead = new Node(o, listHead, null);
}
}
/**
* Adds a new item at the end of the sequence.
*/
public void insertLast(Object o) {
//There is a special case when the sequence is empty.
//Then the both the head and tail pointers needs to be
//initialized to reference the new node.
if (listHead == null) {
listHead = new Node(o, listHead, null);
listTail = listHead;
}
//In the general case, we simply add a new node to the end
//of the list via the tail pointer.
else {
listTail.next = new Node(o, listTail, null);
listTail = listTail.next;
}
}
/**
* Adds a new item at a specified position in the sequence.
*/
public void insert(Object o, int index) throws SequenceDLListException {
//Check the index is positive.
if (index < 0) {
throw new SequenceDLListException("Indexed Element out of Range");
}
//There is a special case when the sequence is empty.
//Then the both the head and tail pointers needs to be
//initialized to reference the new node.
if (listHead == null) {
if (index == 0) {
listHead = new Node(o, listHead, null);
listTail = listHead;
} else {
throw new SequenceDLListException("Indexed element is out of range");
}
}
//There is another special case for insertion at the head of
//the sequence.
else if (index == 0) {
listHead = new Node(o, listHead, null);
}
//In the general case, we need to chain down the linked list
//from the head until we find the location for the new
//list node. If we reach the end of the list before finding
//the specified location, we know that the given index was out
//of range and throw an exception.
else {
Node nodePointer = listHead;
int i = 1;
while (i < index) {
nodePointer = nodePointer.next;
i += 1;
if (nodePointer == null) {
throw new SequenceDLListException("Indexed Element out of Range");
}
}
Node newNode = new Node(o, nodePointer, nodePointer.next);
if (nodePointer.next != null) {
nodePointer.next.prev = newNode;
}
//Now we've found the node before the position of the
//new one, so we 'hook in' the new Node.
nodePointer.next = newNode;
//Finally we need to check that the tail pointer is
//correct. Another special case occurs if the new
//node was inserted at the end, in which case, we need
//to update the tail pointer.
if (nodePointer == listTail) {
listTail = newNode;
}
}
}
/**
* Removes the item at the start of the sequence.
*/
public void deleteFirst() throws SequenceDLListException {
//Check there is something in the sequence to delete.
if (listHead == null) {
throw new SequenceDLListException("Sequence Underflow");
}
//There is a special case when there is just one item in the
//sequence. Both pointers then need to be reset to null.
if (listHead.next == null) {
listHead = null;
listTail = null;
}
//In the general case, we just unlink the first node of the
//list.
else {
listHead = listHead.next;
listHead.prev = null;
}
}
/**
* Removes the item at the end of the sequence.
*/
public void deleteLast() throws SequenceDLListException {
//Check there is something in the sequence to delete.
if (listHead == null) {
throw new SequenceDLListException("Sequence Underflow");
}
//There is a special case when there is just one item in the
//sequence. Both pointers then need to be reset to null.
if (listHead.next == null) {
listHead = null;
listTail = null;
}
//In the general case, we need to chain all the way down the
//list in order to reset the link of the second to last
//element to null.
else {
Node nodePointer = listHead;
while (nodePointer.next != listTail) {
nodePointer = nodePointer.next;
}
//Unlink the last node and reset the tail pointer.
nodePointer.next = null;
listTail = nodePointer;
}
}
/**
* Removes the item at the specified position in the sequence.
*/
public void delete(int index) throws SequenceDLListException {
//Check there is something in the sequence to delete.
if (listHead == null) {
throw new SequenceDLListException("Sequence Underflow");
}
//Check the index is positive.
if (index < 0) {
throw new SequenceDLListException("Indexed Element out of Range");
}
//There is a special case when there is just one item in the
//sequence. Both pointers then need to be reset to null.
if (listHead.next == null) {
if (index == 0) {
listHead = null;
listTail = null;
} else {
throw new SequenceDLListException("Indexed element is out of range.");
}
}
//There is also a special case when the first element has to
//be removed.
else if (index == 0) {
deleteFirst();
}
//In the general case, we need to chain down the list to find
//the node in the indexed position.
else {
Node nodePointer = listHead;
int i = 1;
while (i < index) {
nodePointer = nodePointer.next;
i += 1;
if (nodePointer.next == null) {
throw new SequenceDLListException("Indexed Element out of Range");
}
}
//Unlink the node and reset the tail pointer if that
//node was the last one.
if (nodePointer.next == listTail) {
listTail = nodePointer;
}
//When we remove the node we have to change the reference as well!
if (nodePointer.next.next != null) {
nodePointer.next.next.prev = nodePointer;
}
nodePointer.next = nodePointer.next.next;
}
}
/**
* Returns the item at the start of the sequence.
*/
public Object first() throws SequenceDLListException {
if (listHead != null) {
return listHead.datum;
} else {
throw new SequenceDLListException("Indexed Element out of Range");
}
}
/**
* Returns the item at the end of the sequence.
*/
public Object last() throws SequenceDLListException {
if (listTail != null) {
return listTail.datum;
} else {
throw new SequenceDLListException("Indexed Element out of Range");
}
}
/**
* Returns the item at the specified position in the sequence.
*/
public Object element(int index) throws SequenceDLListException {
//Check the index is positive.
if (index < 0) {
throw new SequenceDLListException("Indexed Element out of Range");
}
//We need to chain down the list until we reach the indexed
//position
Node nodePointer = listHead;
int i = 0;
while (i < index) {
if (nodePointer.next == null) {
throw new SequenceDLListException("Indexed Element out of Range");
} else {
nodePointer = nodePointer.next;
i += 1;
}
}
return nodePointer.datum;
}
/**
* Tests whether there are any items in the sequence.
*/
public boolean empty() {
return (listHead == null);
}
/**
* Returns the number of items in the sequence.
*/
public int size() {
//Chain down the list counting the elements
Node nodePointer = listHead;
int size = 0;
while (nodePointer != null) {
size += 1;
nodePointer = nodePointer.next;
}
return size;
}
/**
* Empties the sequence.
*/
public void clear() {
listHead = null;
listTail = null;
}
}