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.
Related
I have written a code of Binary Search tree that extends comparable and implements an interface. The code for leaves and the helper method countLeaves (included down here), makes sure that all of the test goes through except for one, heightIsLogOfNumLeavesTreeIsPerfect().
// TODO: Look at the Leaves and the helper method to leaves and see how I should change it so that this test goes through aswell.
//EDIT: I have added the whole tree class
java.lang.AssertionError:
Expected: <2>
but: was <0>
Expected :<2>
Actual :<0>
import org.junit.Test;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.Timeout;
import static org.junit.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import java.util.Arrays;
import java.util.stream.IntStream;
/**
* Test class for a tree.
*/
public class TreeTest{
#Rule public Timeout globalTimeout = Timeout.seconds(5);
Tree<Integer> tree;
int[] elementsInTree;
int[] elementsNotInTree;
#Before
public void setUp() {
/**
* This tree should look like this:
*
* 8
* / \
* 3 10
* / \ \
* 1 6 14
* / \ /
* 4 7 13
*/
tree = new Tree<>();
elementsInTree = new int[] {8, 10, 14, 13, 3, 1, 6, 4, 7};
for (int elem : elementsInTree) {
tree.insert(elem);
}
elementsNotInTree = new int[] {34, -3, -10, 12, 74, 5};
}
#Test
public void heightIsLogOfNumLeavesTreeIsPerfect() {
// For a perfect tree, tree.height() == log2(tree.leaves()
// Arrange
Tree<Integer> tree = new Tree<>();
int[] elements = new int[] {8, 3, 10, 1, 6, 9, 14};
int numLeaves = 4;
int logNumLeaves = (int) Math.round(Math.log(numLeaves) / Math.log(2));
for (int elem : elements) {
tree.insert(elem);
}
// Act
int height = tree.height();
// Assert
assertThat(height, equalTo(logNumLeaves));
}
}
**
* An interface describing a generic Comparable
*/
public interface BSTInterface <T>{
boolean search(T elem);
boolean insert(T elem);
int size();
int height();
int leaves();
}
/**
* An Binary Search tree implementation of the comparable interface.
* #param <T>
*/
public class Tree <T extends Comparable <T>> implements BSTInterface <T>{
private int size;
private Node root;
public class Node{
private Node Left;
private Node Right;
private T data;
public Node(T data){
this.data = data;
}
public Node getRight(){
return Right;
}
public Node getLeft() {
return Left;
}
public T getData() {
return data;
}
}
public Tree (){
size = 0;
root = null;
}
/**
* Test for presence of a value.
* #param elem
* #return true/false
*/
#Override
public boolean search(T elem) {
if(root == null ||elem == null){
return false;
}
Node node = root;
while(true){
if(node.data.compareTo(elem) > 0){
if(node.Right == null){
return false;
} else{
node = node.Right;
}
} else if(node.data.compareTo(elem) == 0){
break;
} else{
if(node.Left== null){
return false;
}
else{
node = node.Left;
}
}
}
return true;
}
/**
* Add value to tree; duplicates are not allowed.
* Return true if the element is not already present (and is thus inserted),
* false otherwise.
*
* #param elem
* #return true/false
*/
#Override
public boolean insert(T elem) {
if (elem == null){
return false;
}
if (root == null){
root = new Node(elem);
size++;
return true;
}
Node node = root;
while (true){
if (node.data.compareTo(elem) > 0) {
if (node.Right == null){
node.Right = new Node(elem);
size++;
break;
} else {
node = node.Right;
}
} else if (node.data.compareTo(elem) == 0) {
return false;
} else {
if (node.Left == null){
node.Left = new Node(elem);
size++;
break;
} else {
node = node.Left;
}
}
}
return true;
}
/**
* the number of elements in the tree
* #return size.
*/
#Override
public int size() {
return size;
}
/**
* The height of the tree.
* The empty tree and the tree with only the root node both have height 0.
* #return the height of the tree.
*/
#Override
public int height() {
return countHeight(root);
}
/**
* Helper method for height
*/
private int countHeight(Node node){
if(node == null) {
return 0;
}
return Math.max(countHeight(node.Left), countHeight(node.Right));
}
/**
* The number of leaves in the tree.
* #return the amount of leaves the tree have.
*/
#Override
public int leaves() {
return countLeaves(root);
}
/**
* Helper method for leaves
*/
private int countLeaves(Node node) {
if (node == null) {
return 0;
}
if (node.Left == null && node.Right == null) {
return 1;
}
return countLeaves(node.Left) + countLeaves(node.Right);
}
/**
* A string describing the tree
* #return
*/
public String toString(){
String str = "[" + helpToString(root);
if (str.length() > 1) {
str = str.substring(0, str.length() - 2);
} return str + "]";
}
/**
* Helper method for toString
*/
private String helpToString(Node node) {
String str = "";
if (node != null) {
str += helpToString(node.Right);
str += node.data + ", ";
str += helpToString(node.Left);
}
return str;
}
}
Your countHeight method can return either zero or a maximum of two returns, and there are no other operations in it. You can't get a value greater of zero out of zeros just by using max function.
You should return -1 for an empty tree and max(height(left) + 1, height(right) + 1) otherwise. Each +1 accounts for length of corresponding parent-child edge.
(Mathematically speaking, height of an "empty" tree is usually undefined, but defining it as -1 in this case helps a lot so let's stick to that.)
I have implemented a Binary search tree and I have written a test class (in JUNIT testing) for it. All the test except for one test goes through. The test leavesIsCorrectWhenTreeIsPerfect() gets a message when I debug the code.
Expected: <4> but: was <5> . I do not know have to fix this.
Keep in mind that all the other tests goes through, and I do not think that it is a problem with the tree code.
How do you understand the description for the test?
/**
* A Binary Search tree.
*/
public class Tree <T extends Comparable <T>> implements BinaryTree <T>{
private int size;
private Node root;
public class Node{
private Node Left;
private Node Right;
private T data;
public Node(T data){
this.data = data;
}
}
public Tree (){
size = 0;
root = null;
}
/**
* Test for presence of a value.
* #param elem
* #return true/false
*/
#Override
public boolean search(T elem) {
if(root == null ||elem == null){
return false;
}
Node node = root;
while(true){
if(node.data.compareTo(elem) > 0){
if(node.Right == null){
return false;
} else{
node = node.Right;
}
} else if(node.data.compareTo(elem) == 0){
break;
} else{
if(node.Left== null){
return false;
}
else{
node = node.Left;
}
}
}
return true;
}
/**
* Add value to tree; duplicates are not allowed.
* Return true if the element is not already present (and is thus inserted),
* false otherwise.
*
* #param elem
* #return true/false
*/
#Override
public boolean insert(T elem) {
if (elem == null){
return false;
}
if (root == null){
root = new Node(elem);
size++;
return true;
}
Node node = root;
while (true){
if (node.data.compareTo(elem) > 0) {
if (node.Right == null){
node.Right = new Node(elem);
size++;
break;
} else {
node = node.Right;
}
} else if (node.data.compareTo(elem) == 0) {
return false;
} else {
if (node.Left == null){
node.Left = new Node(elem);
size++;
break;
} else {
node = node.Left;
}
}
}
return true;
}
/**
* The number of elements in the tree
* #return size.
*/
#Override
public int size() {
return size;
}
/**
* The height of the tree.
* The empty tree and the tree with only the root node both have height 0.
* #return the height of the tree.
*/
#Override
public int height() {
return countHeight(root);
}
/**
* Helper method for height
*/
private int countHeight(Node node){
if(node == null) {
return 0;
}
if (node.Left == null && node.Right == null) {
return 0;
}
return 1 + Math.max(countHeight(node.Left), countHeight(node.Right));
}
/**
* The number of leaves in the tree.
* #return the amount of leaves the tree have.
*/
#Override
public int leaves() {
return countLeaves(root);
}
/**
* Helper method for leaves
*/
private int countLeaves(Node node) {
if (node == null) {
return 0;
}
if (node.Left == null && node.Right == null) {
return 1;
}
return countLeaves(node.Left) + countLeaves(node.Right);
}
/**
* A string describing the tree
* #return
*/
public String toString(){
String str = "[" + helpToString(root);
if (str.length() > 1) {
str = str.substring(0, str.length() - 2);
} return str + "]";
}
/**
* Helper method for toString
*/
private String helpToString(Node node) {
String str = "";
if (node != null) {
str += helpToString(node.Right);
str += node.data + ", ";
str += helpToString(node.Left);
}
return str;
}
}
Test class:
import org.junit.Test;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.Timeout;
import static org.junit.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import java.util.Arrays;
import java.util.stream.IntStream;
/**
* Test class for a tree.
*/
public class TreeTest{
#Rule public Timeout globalTimeout = Timeout.seconds(5);
Tree<Integer> tree;
int[] elementsInTree;
int[] elementsNotInTree;
#Before
public void setUp() {
/**
* This tree should look like this:
*
* 8
* / \
* 3 10
* / \ \
* 1 6 14
* / \ /
* 4 7 13
*/
tree = new Tree<>();
elementsInTree = new int[] {8, 10, 14, 13, 3, 1, 6, 4, 7};
for (int elem : elementsInTree) {
tree.insert(elem);
}
elementsNotInTree = new int[] {34, -3, -10, 12, 74, 5};
}
#Test
public void leavesIsTwoWhenPerfectTreeHasThreeNodes() {
// Arrange
Tree<Integer> tree = new Tree<>();
// root must be smaller than one and larger than the other child
tree.insert(1338); // root
tree.insert(1337); // smaller child
tree.insert(1396); // larger child
// Act
int numLeaves = tree.leaves();
// Assert
assertThat(numLeaves, equalTo(2));
}
#Test
public void leavesIsCorrectWhenTreeIsPerfect() { //TEST
// A perfect tree has all leaves at the same depth, and all internal nodes
// (i.e. non-leaves) have two children
//
// This test should assert that a perfect tree with 2*n-1 nodes total,
// has exactly n leaves (i.e. that Tree.leaves() returns n).
//
// An example is the perfect three-node tree from the test above:
//
// (1338)
// / \
// (1337) (1396)
// You have to construct our own tree here, with n >= 4
int n = 4;
int nodes = 2*n-1;
for(int i = 0; i < nodes ; i++) {
tree.insert(i);
}
int leaves = tree.leaves();
assertThat(leaves,equalTo(n));
}
#Test
public void leavesIsOneWhenElementsWereInsertedInAscendingOrder() {
// Arrange
Tree<Integer> tree = new Tree<>();
// insert elements in ascending order => all elements are inserted to the right
int numElements = 100;
for (int i = 0; i < numElements; i++) {
tree.insert(i);
}
// Act
int numLeaves = tree.leaves();
// Assert
assertThat(numLeaves, equalTo(1));
}
// Tests for height
#Test
public void heightIsZeroWhenTreeIsEmpty() {
// Arrange
Tree<Integer> emptyTree = new Tree<>();
// Act
int height = emptyTree.height();
// Assert
assertThat(height, equalTo(0));
}
#Test
public void heightIsLogOfNumLeavesTreeIsPerfect() {
// For a perfect tree, tree.height() == log2(tree.leaves()
// Arrange
Tree<Integer> tree = new Tree<>();
int[] elements = new int[] {8, 3, 10, 1, 6, 9, 14};
int numLeaves = 4;
int logNumLeaves = (int) Math.round(Math.log(numLeaves) / Math.log(2));
for (int elem : elements) {
tree.insert(elem);
}
// Act
int height = tree.height();
// Assert
assertThat(height, equalTo(logNumLeaves));
}
// Tests for insert/height
#Test
public void insertValuesInAscendingOrderIncrementsHeight() {
// When inserting elements in ascending order, each element is inserted
// to the right of the deepest node, so the height should increment by
// 1 for each element inserted.
Tree <Integer> tree = new Tree<>();
int val = 100;
for(int i = 0; i < val; i++){
tree.insert(i);
}
int treeHeight = tree.height();
treeHeight++;
assertThat(val,equalTo(treeHeight));
}
}
The leaves method counts the number of leaves that you have. Your expectation is that there will be four leaves. However, the result is 5. The method that you use in order to count the leaves appears to be correct:
/**
* Helper method for leaves
*/
private int countLeaves(Node node) {
if (node == null) {
return 0;
}
if (node.Left == null && node.Right == null) {
return 1;
}
return countLeaves(node.Left) + countLeaves(node.Right);
}
It essentially counts the items (in a breadth-first-search fashion) that have no children. What could be the reason? Your main thing to find out how your tree looks alike. Based on your insert method:
#Override
public boolean insert(T elem) {
if (elem == null){
return false;
}
if (root == null){
root = new Node(elem);
size++;
return true;
}
Node node = root;
while (true){
if (node.data.compareTo(elem) > 0) {
if (node.Right == null){
node.Right = new Node(elem);
size++;
break;
} else {
node = node.Right;
}
} else if (node.data.compareTo(elem) == 0) {
return false;
} else {
if (node.Left == null){
node.Left = new Node(elem);
size++;
break;
} else {
node = node.Left;
}
}
}
return true;
}
and knowing that 2*n-1 in your test is 7, so the input numbers are 0, 1, 2, 3, 4, 5, 6, it seems to me that the tree could be
0
/
1
/
2
/
3
/
4
/
5
/
6
which would have a single leaf, because if the node has a greater value than the item you are about to insert, then you add it to the node's right. However, the results of your test are different. For some reason you have 5 leaves. You would need to check the reason of that by first finding out how your table looks alike at the end and second by looking into the insert method with a debugger for this input.
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'));
I was doing an assignment in which I'm supposed to create a binary tree and define given functions from its abstract superclass (AbstractBinaryTree.java).
While working on a function called getNumbers() which is basically going to traverse through the whole tree whilst adding values from each node to an array list which it returns. There seems to be a null pointer in one of my if statements.
AbstractBinaryTree.java
import java.util.ArrayList;
public abstract class AbstractBinaryTree
{
protected Node root;
protected int sizeOfTree;
public AbstractBinaryTree()
{
root = null;
sizeOfTree = 0;
}
public int size(){ return sizeOfTree; }
/** compute the depth of a node */
public abstract int depth(Node node);
/** Check if a number is in the tree or not */
public abstract boolean find(Integer i);
/** Create a list of all the numbers in the tree. */
/* If a number appears N times in the tree then this */
/* number should appear N times in the returned list */
public abstract ArrayList<Integer> getNumbers();
/** Adds a leaf to the tree with number specifed by input. */
public abstract void addLeaf(Integer i);
/** Removes "some" leaf from the tree. */
/* If the tree is empty should return null */
public abstract Node removeLeaf();
// these methods are only needed if you wish
// use the TreeGUI visualization program
public int getheight(Node n){
if( n == null) return 0;
return 1 + Math.max(
getheight(n.getLeft()) , getheight(n.getRight())
);
}
public int height(){ return getheight(root); }
}
Node.java File.
public class Node{
protected Integer data;
protected Node left;
protected Node right;
public Node(Integer data)
{
this.data = data;
this.left = this.right = null;
}
public Node(Integer data, Node left, Node right){
this.data = data;
this.left = left;
this.right = right;
}
public Integer getData(){ return this.data; }
public Node getLeft(){ return this.left; }
public Node getRight(){ return this.right; }
public void setLeft(Node left){ this.left = left; }
public void setRight(Node right){ this.right = right; }
public void setData(Integer data){ this.data = data; }
}
BinaryTree.java
import java.util.ArrayList;
import java.util.*;
// Student Name: Adrian Robertson
// Student Number: 101020295
//
// References: Collier, R. "Lectures Notes for COMP1406C- Introduction to Computer Science II" [PDF documents]. Retrieved from cuLearn: https://www.carleton.ca/culearn/(Winter2016).//
// References: http://codereview.stackexchange.com/questions/13255/deleting-a-node-from-a-binary-search-tree
// http://www.algolist.net/Data_structures/Binary_search_tree/Removal
// http://www.geeksforgeeks.org/inorder-tree-traversal- without-recursion-and-without-stack/
public class BinaryTree extends AbstractBinaryTree
{
protected Node root = new Node(12);
public static BinaryTree create()
{
BinaryTree tempTree = new BinaryTree();
//creating all the nodes
Node temp10 = new Node(10);
Node temp40 = new Node(40);
Node temp30 = new Node(30);
Node temp29 = new Node(29);
Node temp51 = new Node(51);
Node temp61 = new Node(61);
Node temp72 = new Node(72);
Node temp31 = new Node(31);
Node temp32 = new Node(32);
Node temp42 = new Node(42);
Node temp34 = new Node(34);
Node temp2 = new Node(2);
Node temp61x2 = new Node(61);
Node temp66 = new Node(66);
Node temp3 = new Node(3);
Node temp73 = new Node(73);
Node temp74 = new Node(74);
Node temp5 = new Node(5);
//setting up the tree
if (tempTree.root.getData() == null)
{
tempTree.root.setData(12);
tempTree.root.setLeft(temp10);
tempTree.root.setRight(temp40);
}
temp10.setLeft(temp30);
temp30.setRight(temp29);
temp29.setRight(temp51);
temp51.setLeft(temp61);
temp51.setRight(temp72);
temp40.setLeft(temp31);
temp31.setLeft(temp42);
temp31.setRight(temp34);
temp34.setLeft(temp61x2);
temp61x2.setLeft(temp66);
temp61x2.setRight(temp73);
temp40.setRight(temp32);
temp32.setRight(temp2);
temp2.setLeft(temp3);
temp3.setRight(temp74);
temp74.setLeft(temp5);
return tempTree;
}
public int depth(Node node)
{
Node current = this.root;
int counter = 1;
while(node != current)
{
if (node.getData() > current.getData())
current = current.getRight();
if (node.getData() < current.getData())
current = current.getLeft();
}
return counter;
}
public boolean find(Integer i)
{
boolean found = false;
Node current = this.root;
if (i == current.getData())
found = true;
while (i != current.getData())
{
if (i > current.getData())
current = current.getRight();
if (i < current.getData())
current = current.getLeft();
if (i == current.getData())
found = true;
}
return found;
}
public ArrayList<Integer> getNumbers()
{
ArrayList<Integer> temp = new ArrayList<Integer>();
Node current = this.root;
Node Pre = new Node(null);
while (current.getData() != null )
{
if (current.getLeft().getData() == null)
{
temp.add(current.getData());
current = current.getRight();
}
else
{
/* Find the inorder predecessor of current */
Pre = current.getLeft();
while(Pre.getRight() != null && Pre.getRight() != current)
Pre = Pre.getRight();
/* Make current as right child of its inorder predecessor */
if (Pre.getRight() == null)
{
Pre.setRight(current);
current = current.getLeft();
}
/* Revert the changes made in if part to restore the original tree i.e., fix the right child of predecssor */
else
{
Pre.setRight(null);
temp.add(current.getData());
current = current.getRight();
}/* End of if condition Pre.right == NULL */
}/* End of if condition current.left == NULL*/
}/*End of while */
Collections.sort(temp);
return temp;
}
public void addLeaf(Integer i)
{
insert(this.root, i);
}
public static void insert(Node node, int value) //insert a node Based on provided argument where node is the root of tree
{
if (node == null)
{
Node first = new Node(value);
node = first;
}
else if (value < node.getData())
{
if (node.left != null)
{
insert(node.left, value);
}
else
{
System.out.println(" > Inserted " + value + " to left of node " + node.getData());
Node newNode = new Node(value);
node.left = newNode;
}
}
else if (value > node.getData())
{
if (node.right != null)
{
insert(node.right, value);
}
else
{
System.out.println(" > Inserted " + value + " to right of node " + node.getData());
Node newNode = new Node(value);
node.right = newNode;
}
}
}
public Node removeLeaf()
{
Node tempA = new Node(61); //create a new node with that value
deleteNodeBST(this.root, 61); //delete the node containing that leaf value
return tempA; //return the copy of that node
}
//delete given node with given value
public boolean deleteNodeBST(Node node, int data) {
ArrayList<Integer> temp = this.getNumbers();
if (node == null) {
return false;
}
if (node.getData() == data) {
if ((node.getLeft() == null) && (node.getRight() == null)) {
// leaf node
node = null;
return true;
}
if ((node.getLeft() != null) && (node.getRight() != null)) {
// node with two children
node.setData(temp.get(0));
return true;
}
// either left child or right child
if (node.getLeft() != null) {
this.root.setLeft(node.getLeft());
node = null;
return true;
}
if (node.getRight() != null) {
this.root.setRight(node.getRight());
node = null;
return true;
}
}
this.root = node;
if (node.getData() > data) {
return deleteNodeBST(node.getLeft(), data);
} else {
return deleteNodeBST(node.getRight(), data);
}
}
public static void main(String args[])
{
BinaryTree myTree = new BinaryTree();
myTree.create();
System.out.println(myTree.getNumbers());
}
}
The create function creates a binary tree and returns that binary tree. This is the predefined binary tree that I was supposed to create according to assignment guidelines. I understand that the tree values are not organised properly as they would be in a proper binary tree. Is that was causes the null pointer during traversal? Cause the traversal is taylored to work for a proper Binary tree.
In class BinaryTree, you initialize the left and right of your root node only if the haven't data. But the root node is create with data...
You should invert the condition in :
//setting up the tree
if (tempTree.root.getData() == null)
And add a test in getNumbers() :
if (current.getLeft() == null || current.getLeft().getData() == null)
In the BinaryTree class, getNumbers() method and while loop. Maybe your problem is here:
if (current.getLeft().getData() == null) {
temp.add(current.getData());
current = current.getRight();
}
When you call current.getLeft(), it will return null when the left Node is null. And then, you call getData() it will throw a NullPointerException. If you're not sure that it always not null check it before you call any methods of it. Example you can change the if statement to:
if (current.getLeft() != null && current.getLeft().getData() == null) {
temp.add(current.getData());
current = current.getRight();
}
Or:
Node left = current.getLeft();
if (left == null) {
//TODO something here
} else if (left.getData() == null) {
temp.add(current.getData());
current = current.getRight();
}
Please update your getNumbers - method accordingly,
You need to put right checks before work with reference type.
public ArrayList<Integer> getNumbers()
{
ArrayList<Integer> temp = new ArrayList<Integer>();
Node current = this.root;
Node Pre = new Node(null);
while (current != null && current.getData() != null ) // Fix here... Add : current != null
{
if (current.getLeft() != null && current.getLeft().getData() == null) // Fix here... Add : current.getLeft() != null
{
temp.add(current.getData());
current = current.getRight();
}
else
{
/* Find the inorder predecessor of current */
Pre = current.getLeft();
while(Pre != null && Pre.getRight() != null && Pre.getRight() != current) // Fix here... Add : Pre != null
Pre = Pre.getRight();
/* Make current as right child of its inorder predecessor */
if (Pre != null && Pre.getRight() == null) // Fix here... Add : Pre != null
{
Pre.setRight(current);
current = current.getLeft();
}
/* Revert the changes made in if part to restore the original tree i.e., fix the right child of predecssor */
else
{
if(Pre != null){ // Fix here... Add : Pre != null
Pre.setRight(null);
}
temp.add(current.getData());
current = current.getRight();
}/* End of if condition Pre.right == NULL */
}/* End of if condition current.left == NULL*/
}/*End of while */
Collections.sort(temp);
return temp;
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I am looking for some help with a class I have designed for an assignment. It adds game scores to a linked list and lists them from highest to lowest. The max number of scores is 10. I have it almost working but I can't figure something out. I add the first score and it works, then if I add a second score, it only works if that score is higher than the first. If not, it throws a java.lang.NullPointerException. Can someone take a look at my insert(String name, int score) method and let me know what the problem is?
public class GamerList {
/**
* The node class stores a list element and a reference to the next node.
* #author johnmckillip
*
*/
private class Node {
String name;
int score;
Node next;
/**
* Constructor.
* #param val The element to store in the node.
* #param n The reference to the successor node.
*/
Node(String val1, int val2, Node n) {
name = val1;
score = val2;
next = n;
}
/**
* Constructor.
* #param val The element to store in the node.
*/
Node(String val1, int val2) {
this(val1, val2, null);
}
}
private Node head;
private Node tail;
/**
* Constructor.
*/
public GamerList() {
head = null;
tail = null;
}
/**
* The isEmpty method checks to see if the list is empty.
* #return true if the list is empty, false otherwise.
*/
public boolean isEmpty() {
return head == null;
}
/**
* The size method returns the length of the list.
* #return The number of elements in the list.
*/
public int size() {
int count = 0;
Node p = head;
while(p != null) {
count++;
p = p.next;
}
return count;
}
public void insert(String name, int score) {
Node node = new Node(name, score);
if(isEmpty()) {
head = node;
tail = node;
}
else if(head.score <= node.score) {
node.next = head;
head = node;
}
else {
Node frontPtr = head.next;
Node backPtr = head;
while(frontPtr.score > node.score && frontPtr.next != null) {
backPtr = backPtr.next;
frontPtr = frontPtr.next;
}
if(frontPtr != null && frontPtr.score <= node.score) {
backPtr.next = node;
node.next = frontPtr;
}
else {
frontPtr.next = node;
tail = node;
}
}
if(size() > 10) {
Node currentPtr = head;
while(currentPtr.next != tail) {
currentPtr = currentPtr.next;
}
tail = currentPtr;
currentPtr.next = null;
}
}
public void printList() {
Node temp = head;
while(temp != null) {
System.out.print(temp.name + " " + temp.score + " ");
System.out.println("");
temp = temp.next;
}
}
}
Here is my class to test GamerList:
public class TestGamerList {
/**
* #param args
*/
public static void main(String[] args) {
GamerList list1 = new GamerList();
list1.insert("Fry", 89);
list1.insert("Bender", 25);
list1.insert("Leela", 90);
list1.insert("Zoidburg", 23);
list1.insert("Amy", 34);
list1.insert("Hermes", 96);
list1.insert("Zapp",123);
list1.insert("Nibbler", 56);
list1.insert("Calculon", 12);
list1.insert("Hypnotoad", 189);
list1.insert("Lrrr", 5);
list1.insert("Scruffy", 28);
System.out.println("Top 10 Scores: ");
list1.printList();
}
}
Looks like you don't set head's next. That's one problem. The second is, even if you do that, you'll get into infinite loop, 'cause you have done the insertion logic incorrectly. I've changed you insert() a bit to make it work, but that still lacks elegance and is far from effective implementation. For example, on every insertion after you've got 10 elements you are running size() which makes your code complexity increase by a factor of approx. N = size(). If you really want to do that, make size a variable and just increase it at the end of every insert(). Anyway, edited code:
public class GamerList {
private class Node {
String name;
int score;
Node next;
Node(String val1, int val2, Node n) {
name = val1;
score = val2;
next = n;
}
Node(String val1, int val2) {
this(val1, val2, null);
}
}
private Node head;
private Node tail;
/**
* Constructor.
*/
public GamerList() {
head = null;
tail = null;
}
/**
* The isEmpty method checks to see if the list is empty.
* #return true if the list is empty, false otherwise.
*/
public boolean isEmpty() {
return head == null;
}
/**
* The size method returns the length of the list.
* #return The number of elements in the list.
*/
public int size() {
int count = 0;
Node p = head;
while(p != null) {
count++;
p = p.next;
}
return count;
}
public void insert(String name, int score) {
Node node = new Node(name, score);
if(isEmpty()) {
head = node;
head.next = tail;
}
else if(head.score <= node.score) {
node.next = head;
head = node;
}
else {
Node beforeNode = head;
while(beforeNode.score > node.score && beforeNode.next != null) {
beforeNode = beforeNode.next;
}
node.next = beforeNode.next;
beforeNode.next = node;
}
if(size() > 10) {
Node currentPtr = head;
for (int i = 0; i < 9; i++) {
currentPtr = currentPtr.next;
}
currentPtr.next = null;
}
}
public void printList() {
Node temp = head;
while(temp != null) {
System.out.print(temp.name + " " + temp.score + " ");
System.out.println("");
temp = temp.next;
}
}
}
Without stack trace is complex.
but probably error is here
while(frontPtr.score > node.score && frontPtr.next != null)
since frontPtr is null.
add a check on the
if (frontPtr!=null)
while(frontPtr.score > node.score && frontPtr.next != null)