Question: Need help with my java project. 2. Implement the add, contains, and remove methods. 3. Complete the block comments for contains and remove methods. 4.
Need help with my java project.
2. Implement the add, contains, and remove methods. 3. Complete the block comments for contains and remove methods. 4. Complete the header comment.
Recursive definition of Binary Search Tree:
A set of nodes T is a binary search tree if either of the following are true: T is empty If T is not empty, its root node has two subtrees, Tleft and Tright, such that Tleft and Tright are binary search trees and the value in the root node of T is greater than all values in Tleft and is less than all values in Tright. The nodes of the tree are a set (no duplicate values).
Why use a Binary Search Tree?
The reasoning for storing values in a search tree is to minimize the number of steps required to find the item. In a worst case scenario, we would have to take a number of steps equal to the height of the tree. Ideally the tree is Balanced, meaning both left and right subtrees have about the same height and most of the nodes up until the last level are full. A Complete binary tree is a good example of a Balanced tree. By observing the fact that the number of nodes at each level of the tree double when the tree is Balanced, then the size (n) of the tree is n = 2 ^ height. If we solve for the height of the tree, we get the worst case scenario for searching a balanced tree: O(log n).
Recursive algorithm for searching a Binary Search Tree:
1. If the root is null, return false 2. If the target is equal to root.data, return true 3. Else if the target is less than root.data, return the result of searching the left subtree 4. Else return the result of searching the right subtree.
Keep in mind that the term "root" does not necessarily refer to the root field of the BinarySearchTree.java class. It refers instead to the recursive definition of a binary search tree where every subtree is a binary tree with its own root.
Example for searching a Binary Search Tree:
lay /\ /\ /\ house rat
/\ /\ /\/\ /\/\
cow jack milked that
If we wish to see if the tree contains "jack", first compare "jack" with "lay". Because "jack" is less than "lay", we continue the search with the left subtree and compare "jack" with "house". Because "jack" is greater than "house", we continue with the right subtree and compare "jack" with "jack". Since they are equal, we
return true. However, if we were searching for "jill", we would have continued down the same path, and seeing that "jill" is greater than "jack", have tried to search the empty subtree on the right and thus concluded "jill" is not in the tree.
Recursive algorithm for insertion into a Binary Search Tree:
1. If the root is null, replace empty tree with a new tree with the item at the root and return true 2. Else if the item is equal to the data at the root, then the item is already in the tree; return false
3. Else if the item is less than root.data, return the result of inserting the item in the left subtree 4. Else return the result of inserting the item in the right subtree
This is a generic algorithm. It does not take into account our particular implementation of the BinarySearchTree class. Implementation options: Option A: Check in advance if the child is null. If it is, assign it a new Node with the given item and return true.
Option B: Do not check in advance if the child is null. Instead, reassign the child to be the result of calling a private add method on the child. Since the public add method returns a boolean, but this strategy returns a Node, you will need to create a global boolean flag which will be used to indicate if the item has been inserted (true) or is a duplicate (false).
For example: private Nodeadd(Node node, E item){
// If node is null, set the flag to true, return a new node with the item // If the item is already in node, set the flag to false, return node // Otherwise, call add(child) on the appropriate subtree of node and then // return the node. i.e. node.left = add(node.left, item); return node;
}
Recursive algorithm for removal from a Binary Search Tree:
1. If the root is null, return false 2. Else if the item is less than the root, return the result of removing from the left subtree 3. Else if the item is greater than the root, return the result of removing from the right subtree 4. Else, the item must equal the root, and the root needs to be removed. 4a. If the root has no children, the root becomes null. 4b. If the root has a single child, the root becomes that child. 4c. If the root has two children, the root becomes the largest value in its left subtree. (Hint: Its called the inorder predecessor and its always located in the same place.) The node containing that value must also be removed. Return true. As with the add method, Options A and B apply here as well.
Tips:
Figure out your base cases (i.e. when you don't recurse). If you have a base case where the given node is null, check that base case first to avoid null pointer exceptions. Use pencil and paper to come up with examples to use for crafting your algorithm. If you hit a bug, use the Debugger to find the problem, then refine your algorithm.
Given code:
import java.util.ArrayList;
/**
* Class for a binary tree that stores type E objects.
*
* @param
* The element type
*/
public class BinaryTree
static protected class Node
protected E data;
protected Node
protected Node
public Node(E data) {
this.data = data;
left = right = null;
}
}
protected Node
/**
* Constructs an empty binary tree;
*/
public BinaryTree() {
}
/**
* Constructs a binary tree with the given data at the root.
*
* @param data
* data for the root of the new tree.
*/
public BinaryTree(E data) {
this.root = new Node
}
/**
* Constructs a binary tree with the given data at the root and the two
* given subtrees.
*
* @param data
* data for the root of the new tree.
* @param leftTree
* left binary subtree. Null indicates empty subtree.
* @param rightTree
* right binary subtree Null indicates empty subtree.
*/
public BinaryTree(E data, BinaryTree
root = new Node
root.left = leftTree == null ? null : leftTree.root;
root.right = rightTree == null ? null : rightTree.root;
}
/**
* Constructs a binary tree with the given node as the root.
*
* @param root
* root node of the new tree.
*/
protected BinaryTree(Node
this.root = root;
}
/**
* Returns the data held in the root of the tree.
*
* @return data in the root of the tree.
*/
public E getData() {
return root.data;
}
/**
* A tree is a leaf if it has a root and it's left and right subtrees are
* empty (null). An empty tree is not considered to be a leaf.
*
* @return true if tree is a leaf, false otherwise
*/
public boolean isLeaf() {
return isLeaf(root);
}
protected boolean isLeaf(Node
if (root == null) {
return false;
}
return root.left == null && root.right == null;
}
/**
* The height of a tree is the number of nodes in the longest path from the
* root node to a leaf node.
*
* @return the height of the tree
*/
public int getHeight() {
return getHeight(root);
}
protected int getHeight(Node
if (root == null) {
return 0;
}
return 1 + Math.max(getHeight(root.left), getHeight(root.right));
}
public int getSize() {
return getSize(root);
}
protected int getSize(Node
if (root == null) {
return 0;
}
return 1 + getSize(root.left) + getSize(root.right);
}
/**
* Method to return the in-order traversal of the binary tree as a list of
* elements. (Left, Root, Right)
*
* @return A in-order traversal as a string
*/
public ArrayList
return inOrderTraverse(root);
}
protected ArrayList
ArrayList
if (root == null) {
return elements;
}
elements.addAll(inOrderTraverse(root.left));
elements.add(root.data);
elements.addAll(inOrderTraverse(root.right));
return elements;
}
/**
* Method to return the pre-order traversal of the binary tree as a list of
* elements. (Root, Left, Right)
*
* @return A pre-order traversal as a string
*/
public ArrayList
return preOrderTraverse(root);
}
protected ArrayList
ArrayList
if (root == null) {
return elements;
}
elements.add(root.data);
elements.addAll(preOrderTraverse(root.left));
elements.addAll(preOrderTraverse(root.right));
return elements;
}
/**
* Method to return the post-order traversal of the binary tree as a list of
* elements. (Left, Right, Root)
*
* @return A post-order traversal as a string
*/
public ArrayList
return postOrderTraverse(root);
}
protected ArrayList
ArrayList
if (root == null) {
return elements;
}
elements.addAll(postOrderTraverse(root.left));
elements.addAll(postOrderTraverse(root.right));
elements.add(root.data);
return elements;
}
/**
* A binary tree is full if every node has either 0 or 2 children. An empty
* binary tree is not full.
*
* @return true if binary tree is full, false otherwise
*/
public boolean isFull() {
return isFull(root);
}
protected boolean isFull(Node
if (root == null) {
return false;
}
return isLeaf(root) || isFull(root.left) && isFull(root.right);
}
/**
* A complete binary tree is a binary tree whose all levels except the last
* level are completely filled and all the leaves in the last level are all
* to the left side. The empty tree is not a complete tree.
*
* @return true if binary tree is complete, false otherwise
*/
public boolean isComplete() {
int size = getSize();
if (root == null) {
return false;
}
return isComplete(root, 0, size);
}
protected boolean isComplete(Node
if (root == null) {
return true;
}
if (index >= size) {
return false;
}
return isComplete(root.left, 2 * index + 1, size)
&& isComplete(root.right, 2 * index + 2, size);
}
}
Tester code:
import static org.junit.Assert.*;
import org.junit.Test;
import project4.BinaryTree.Node;
public class BinaryTreeTest {
@Test
public void testBinaryTree() {
BinaryTree
assertNull(tree.root);
}
@Test
public void testBinaryTreeE() {
BinaryTree
assertEquals("hi", tree.root.data);
assertNull(tree.root.right);
assertNull(tree.root.left);
}
@Test
public void testBinaryTreeEBinaryTreeOfEBinaryTreeOfE() {
BinaryTree
Node
leftTree.root = leftNode;
BinaryTree
Node
rightTree.root = rightNode;
BinaryTree
assertEquals("tree1", tree1.root.data);
assertEquals(leftTree.root, tree1.root.left);
assertEquals(rightTree.root, tree1.root.right);
BinaryTree
assertNull(tree2.root.right);
assertNull(tree2.root.left);
}
@Test
public void testBinaryTreeNodeOfE() {
Node
BinaryTree
assertEquals(node, tree.root);
assertEquals("hi", tree.root.data);
}
@Test
public void testGetData() {
Node
BinaryTree
assertEquals("hi", tree.getData());
}
@Test
public void testIsLeaf() {
BinaryTree
/*
* Not Leaf
* empty tree
*/
assertFalse(tree.isLeaf());
/*
* Leaf
* root
*/
Node
tree.root = root;
assertTrue(tree.isLeaf());
/*
* Not Leaf
* root
* /
*/
Node
tree.root.left = child;
tree.root.right = null;
assertFalse(tree.isLeaf());
/*
* Not Leaf
* root
* \
*/
tree.root.left = null;
tree.root.right = child;
assertFalse(tree.isLeaf());
/*
* Not Leaf
* root
* / \
*/
tree.root.left = child;
tree.root.right = child;
assertFalse(tree.isLeaf());
}
@Test
public void testGetHeight() {
BinaryTree
Node
Node
Node
Node
Node
Node
assertEquals(0, tree.getHeight());
tree.root = root;
assertEquals(1, tree.getHeight());
/*
* 1 root
* 2 /
*/
root.left = node2;
assertEquals(2, tree.getHeight());
/*
* 1 root
* 2 / \
*/
root.right = node3;
assertEquals(2, tree.getHeight());
/*
* 1 root
* 2 / \
* 3 \
*/
node2.right = node4;
assertEquals(3, tree.getHeight());
/*
* 1 root
* 2 / \
* 3 \ /
*/
node3.left = node5;
assertEquals(3, tree.getHeight());
/*
* 1 root
* 2 / \
* 3 \ /
* 4 \
*/
node5.left = node6;
assertEquals(4, tree.getHeight());
}
@Test
public void testGetSize() {
BinaryTree
Node
Node
Node
Node
Node
Node
assertEquals(0, tree.getSize());
tree.root = root;
assertEquals(1, tree.getSize());
/*
* 1 root
* 2 /
*/
root.left = node2;
assertEquals(2, tree.getSize());
/*
* 1 root
* 23 / \
*/
root.right = node3;
assertEquals(3, tree.getSize());
/*
* 1 root
* 23 / \
* 4 \
*/
node2.right = node4;
assertEquals(4, tree.getSize());
/*
* 1 root
* 23 / \
* 45 \ /
*/
node3.left = node5;
assertEquals(5, tree.getSize());
/*
* 1 root
* 23 / \
* 45 \ /
* 6 \
*/
node5.left = node6;
assertEquals(6, tree.getSize());
}
@Test
public void testInOrderTraverse() {
BinaryTree
Node
Node
Node
Node
Node
tree.root = node1;
node1.left = node2;
node1.right = node3;
node2.left = node4;
node2.right = node5;
Integer[] expecteds = {4, 2, 5, 1, 3};
Integer[] actuals = new Integer[5];
actuals = tree.inOrderTraverse().toArray(actuals);
assertArrayEquals(expecteds, actuals);
}
@Test
public void testPreOrderTraverse() {
BinaryTree
Node
Node
Node
Node
Node
tree.root = node1;
node1.left = node2;
node1.right = node3;
node2.left = node4;
node2.right = node5;
Integer[] expecteds = {1, 2, 4, 5, 3};
Integer[] actuals = new Integer[5];
actuals = tree.preOrderTraverse().toArray(actuals);
assertArrayEquals(expecteds, actuals);
}
@Test
public void testPostOrderTraverse() {
BinaryTree
Node
Node
Node
Node
Node
tree.root = node1;
node1.left = node2;
node1.right = node3;
node2.left = node4;
node2.right = node5;
Integer[] expecteds = {4, 5, 2, 3, 1};
Integer[] actuals = new Integer[5];
actuals = tree.postOrderTraverse().toArray(actuals);
assertArrayEquals(expecteds, actuals);
}
@Test
public void testIsFull() {
BinaryTree
/*
* Not Full
* empty tree
*/
assertFalse(tree.isFull());
/*
* Full
* root
*/
Node
tree.root = root;
assertTrue(tree.isFull());
/*
* Not Full
* root
* /
*/
Node
root.left = node2;
assertFalse(tree.isFull());
/*
* Full
* root
* / \
*/
Node
root.right = node3;
assertTrue(tree.isFull());
/*
* Not Full
* root
* / \
* /
*/
Node
node2.left = node4;
assertFalse(tree.isFull());
/*
* Full
* root
* / \
* /\
*/
Node
node2.right = node5;
assertTrue(tree.isFull());
/*
* Not Full
* root
* \
* /\
*/
root.left = null;
root.right = node2;
assertFalse(tree.isFull());
/*
* Full
* root
* / \
* /\
*/
root.left = node3;
assertTrue(tree.isFull());
}
@Test
public void testIsComplete() {
BinaryTree
/*
* Not Complete
* empty tree
*/
assertFalse(tree.isComplete());
/*
* Complete
* root (0)
*/
Node
tree.root = node0;
assertTrue(tree.isComplete());
/*
* Complete
* 0
* /
* 1
*/
Node
node0.left = node1;
assertTrue(tree.isComplete());
/*
* Complete
* 0
* / \
* 1 2
*/
Node
node0.right = node2;
assertTrue(tree.isComplete());
/*
* Complete
* 0
* / \
* 1 2
* /
* 3
*/
Node
node1.left = node3;
assertTrue(tree.isComplete());
/*
* Complete
* 0
* / \
* 1 2
* / \
* 3 4
*/
Node
node1.right = node4;
assertTrue(tree.isComplete());
/*
* Complete
* 0
* / \
* 1 2
* /\ /
* 3 4 5
*/
Node
node2.left = node5;
assertTrue(tree.isComplete());
/*
* Not Complete
* 0
* / \
* 1 2
* \ /
* 4 5
*/
node1.left = null;
assertFalse(tree.isComplete());
/*
* Not Complete
* 0
* / \
* 1 2
* / \
* 5 6
*/
node1.right = null;
Node
node2.right = node6;
assertFalse(tree.isComplete());
}
}
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
