I am implementing an AVL Tree of the following type AVLTree<K extends Comparable<K>,V> basically every node of the Tree is a Key-Value Node, at the moment i am struggling with a method that deletes all the V values. This is what i have:
private void deleteAll(AVLTreeNode<K,V> root, V value){
if(root == null) return;
deleteAll(root.left, value);
deleteAll(root.right, value);
if(root.getValue().equals(value)){
delete(root.getKey());
}
}
Super easy approach (maybe not optimized O(nlog(n)) if you have a better optimized solution feel free to write it) using a bottom-up recursion.
The delete method:
public void delete(K key){
super.setRoot(delete(super.getRoot(), key));
}
private AVLTreeNode<K,V> delete(AVLTreeNode<K,V> root, K key) {
if (root == null) {
return root;
} else if (root.getKey().compareTo(key) > 0) {
root.setLeft(delete(root.left, key));
} else if (root.getKey().compareTo(key) < 0) {
root.setRight(delete(root.right, key));
} else {
if (root.left == null || root.right == null) {
root = (root.left == null) ? root.right : root.left;
} else {
AVLTreeNode<K,V> mostLeftChild = AVLTreeUtils.minValueNode(root.right);
root.key = mostLeftChild.getKey();
root.value = mostLeftChild.getValue();
root.setRight(delete(root.right, root.key));
}
size--;
}
if (root != null) {
root = AVLTreeUtils.rebalance(root);
}
return root;
}
What happens is that it deletes correclty most of the values but sometimes it lefts some of the values it had to delete there, here is one example:
DELETING ALL VALUES: 2
BEFORE DELETION OF EVERY: 2
->2
->0
->1
->2
->1
->1
->1
->0
->2
->2
AFTER DELETION
->2
->0
->1
->2
->1
->1
->1
->0
Time used: 0 ms tree size: 8
-------------------------------------------
Does tree contain value: 2? true
EDIT:
Here is all the code of the class
package structure.tree.balanced;
import structure.array.Array;
import structure.node.Node;
import structure.tree.Tree;
public class AVLTree<K extends Comparable<K>,V> extends Tree<AVLTree.AVLTreeNode<K, V>> {
private static final long serialVersionUID = 5046115177325966348L;
public boolean containsValue(V value) {
return containsValue(((AVLTreeNode<K,V>) super.getRoot()), value);
}
private boolean containsValue(AVLTreeNode<K,V> root, V value){
if(root == null) return false;
else {
if(root.getValue().equals(value)) return true;
else return containsValue(root.getLeft(), value) || containsValue(root.getRight(), value);
}
}
public boolean containsKey(K key){
return containsKey(((AVLTreeNode<K,V>) super.getRoot()), key);
}
private boolean containsKey(AVLTreeNode<K,V> root, K key){
if(root == null) return false;
else {
if(root.getKey().compareTo(key) < 0) return containsKey(root.getRight(), key);
else if(root.getKey().compareTo(key) > 0) return containsKey(root.getLeft(), key);
else return true;
}
}
public void delete(K key){
super.setRoot(delete(super.getRoot(), key));
}
private AVLTreeNode<K,V> delete(AVLTreeNode<K,V> root, K key) {
if (root == null) {
return root;
} else if (root.getKey().compareTo(key) > 0) {
root.setLeft(delete(root.left, key));
} else if (root.getKey().compareTo(key) < 0) {
root.setRight(delete(root.right, key));
} else {
if (root.left == null || root.right == null) {
root = (root.left == null) ? root.right : root.left;
} else {
AVLTreeNode<K,V> mostLeftChild = minValueNode(root.right);
root.key = mostLeftChild.getKey();
root.value = mostLeftChild.getValue();
root.setRight(delete(root.right, root.key));
}
if(size > 0) size--;
}
if (root != null) {
root = rebalance(root);
}
return root;
}
public void deleteAll(V value){
deleteAll(super.getRoot(), value);
}
private void deleteAll(AVLTreeNode<K,V> root, V value){
if(root == null) return;
deleteAll(root.left, value);
deleteAll(root.right, value);
if(root.getValue().equals(value)) delete(root.getKey());
}
public V get(K key){
return get(super.getRoot(), key);
}
private V get(AVLTreeNode<K, V> root, K key) {
if(root.getKey().compareTo(key) == 0) return root.getValue();
else if(root.getKey().compareTo(key) > 0) return get(root.getLeft(), key);
else return get(root.getRight(), key);
}
private int getBalance(AVLTreeNode<K,V> n) {
return (n == null) ? 0 : height(n.getRight()) - height(n.getLeft());
}
private int height(AVLTreeNode<K,V> n) {
return n == null ? -1 : n.getHeight();
}
public void insert(K key, V value) {
size++;
super.setRoot(insert(super.getRoot(), key, value));
}
private AVLTreeNode<K,V> insert(AVLTreeNode<K,V> root, K key, V value){
if (root == null) {
return new AVLTreeNode<K,V>(key, value);
} else if (root.getKey().compareTo(key) > 0) {
root.setLeft(insert(root.getLeft(), key, value));
} else if (root.getKey().compareTo(key) < 0) {
root.setRight(insert(root.getRight(), key, value));
} else {
size--;
throw new RuntimeException("duplicate Key!");
}
return rebalance(root);
}
private AVLTreeNode<K,V> minValueNode(AVLTreeNode<K,V> root){
if(root == null) return null;
else {
if(root.getLeft() != null) return minValueNode(root.getLeft());
else return root;
}
}
private AVLTreeNode<K,V> rebalance(AVLTreeNode<K,V> z) {
updateHeight(z);
int balance = getBalance(z);
if (balance > 1) {
if (height(z.getRight().getRight()) > height(z.getRight().getLeft())) {
z = rotateLeft(z);
} else {
z.setRight(rotateRight(z.getRight()));
z = rotateLeft(z);
}
} else if (balance < -1) {
if (height(z.getLeft().getLeft()) > height(z.getLeft().getRight()))
z = rotateRight(z);
else {
z.setLeft(rotateLeft(z.getLeft()));
z = rotateRight(z);
}
}
return z;
}
public void replace(K key, V newValue) {
replace(super.getRoot(), key, newValue);
}
private void replace(AVLTreeNode<K, V> root, K key, V newValue) {
if(root != null){
if(root.getKey().compareTo(key) == 0) root.setValue(newValue);
else if(root.getKey().compareTo(key) > 0) replace(root.getLeft(), key, newValue);
else replace(root.getRight(), key, newValue);
}
}
public void replaceAll(V oldValue, V newValue){
replaceAll(super.getRoot(), oldValue, newValue);
}
private void replaceAll(AVLTreeNode<K, V> root, V oldValue, V newValue){
if(root == null) return;
if(root.getValue().equals(oldValue)) root.setValue(newValue);
replaceAll(root.left, oldValue, newValue);
replaceAll(root.right, oldValue, newValue);
}
private AVLTreeNode<K,V> rotateLeft(AVLTreeNode<K,V> y){
AVLTreeNode<K,V> x = y.getRight();
AVLTreeNode<K,V> z = x.getLeft();
x.setLeft(y);
y.setRight(z);
updateHeight(y);
updateHeight(x);
return x;
}
private AVLTreeNode<K,V> rotateRight(AVLTreeNode<K,V> y){
AVLTreeNode<K,V> x = y.getLeft();
AVLTreeNode<K,V> z = x.getRight();
x.setRight(y);
y.setLeft(z);
updateHeight(y);
updateHeight(x);
return x;
}
public Object[] toArray(){
return toArray(super.getRoot(), new Array<>(size()));
}
private Object[] toArray(AVLTreeNode<K,V> root, Array<AVLTreeNode<K,V>> arr){
if(root != null){
toArray(root.left, arr);
arr.insert(root);
toArray(root.right, arr);
}
return arr.toArray();
}
private void updateHeight(AVLTreeNode<K,V> root){
root.setHeight(1 + Math.max(height(root.getLeft()), height(root.getRight())));
}
public static class AVLTreeNode<K extends Comparable<K>, V> implements Node<V> {
private static final long serialVersionUID = -2099221188924293375L;
private AVLTreeNode<K,V> left, right;
private K key;
private V value;
private int height = 0;
public AVLTreeNode(K key, V value){
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
#SuppressWarnings("unused")
private void setKey(K key) {
this.key = key;
}
public AVLTreeNode<K,V> getLeft() {
return left;
}
protected void setLeft(AVLTreeNode<K,V> left) {
this.left = left;
}
public AVLTreeNode<K,V> getRight() {
return right;
}
protected void setRight(AVLTreeNode<K,V> right) {
this.right = right;
}
#Override
public String toString() {
return "{\"key\":"+key+",\"value\":"+getValue()+"}";
}
#Override
public V getValue() {
return value;
}
#Override
public void setValue(V value) {
this.value = value;
}
public int getHeight() {
return height;
}
protected void setHeight(int height) {
this.height = height;
}
public int getBalance() {
return (left != null ? left.getHeight() : 0) - (right != null ? right.getHeight() : 0);
}
}
}
The superclass is this:
package structure.tree;
import structure.Structure;
import structure.node.Node;
/**
* A Tree is a {#Structure} that uses {#Node} as value.
*/
public abstract class Tree<N extends Node<?>> {
private static final long serialVersionUID = -2524427972418434522L;
private N root;
public void clear() {
root = null;
size = 0;
}
public boolean isEmpty() {
return size == 0;
}
public N getRoot() {
return root;
}
protected void setRoot(N value) {
this.root = value;
}
}
This is the code i run that gives problems note that sometimes it works and sometimes it doesnt:
AVLTree<Integer,Integer> avlt = new AVLTree<Integer,Integer>();
Random r = new Random();
for(int i = 1; i <= SIZE; i++){
avlt.insert(i, r.nextInt(keySize));
}
int vdel = r.nextInt(keySize);
avlt.deleteAll(vdel);
assertEquals(false, avlt.containsValue(vdel));
The problem is that the tree structure changes whilst you are trying to find nodes to delete.
Consider this tree, from which we will be deleting the 'X's:
2->X
/ \
1->X 3->X
\
4->O
The delete operation starts at '2'. As the '2' node has a left hand branch, we descend to the '1' node. The '1' node has neither left nor right branches so there is no further descent.
Node '1' must be deleted.
2->X
\
3->X
\
4->O
And then the tree needs rebalancing.
3->X
/ \
2->X 4->O
This completes the processing of the '1' node, so the recursive search moves back to '2'.
The left hand branch has been processed. Due to the rebalancing, there is no longer a right hand branch to process. The '2' node itself needs deleting.
3->X
\
4->O
This completes the processign of node '2' so we return. This completes the algorithm.
Nodes '3' and '4' were never inspected because of the rebalancing.
How to fix this?
The easiest solution is to separate the search from the "delete and rebalance" operation. Create a collection of all the keys that map to the value to be deleted. Once all such keys are identified, delete those mappings one at a time. As the tree does not change shape during the search, the search will find all the relevant key-value pairs.
My own preference would be to create an Iterator over the tree nodes that supports remove. Such an Iterator would be useful for tasks beyond deleting matching values. For such an iterator one needs to be able to identify the next node from any specified node. This means a node has to know what its parent is.
To that end, I suggest amending your code as follows:
The node implementation tracks its parent and its key cannot be changed.
public static class AVLTreeNode<K extends Comparable<K>, V> implements Node<V> {
private AVLTreeNode<K,V> left, right, parent;
private final K key;
private V value;
private int height = 0;
public AVLTreeNode(K key, V value){
this.key = key;
this.value = value;
}
protected void setLeft(AVLTreeNode<K,V> left) {
this.left = left;
if( left!=null ) {
left.parent = this;
}
}
public AVLTreeNode<K,V> getNext() {
AVLTreeNode<K,V> next;
// If a right branch exists, the next node is the left-most node in the right branch.
if( right!=null ) {
next = right;
while( next.left!=null ) {
next = next.left;
}
return next;
}
// The closest parent of which this is a left-branch descendant is the next node
next = this;
while( next.parent!=null ) {
if( next.parent.left==next ) {
return next.parent;
}
next = next.parent;
}
// no next node
return null;
}
protected void setRight(AVLTreeNode<K,V> right) {
this.right = right;
if( right!=null ) {
right.parent = this;
}
}
... rest of class is unchanged
}
The tree's insert and delete method can move a node to the root of the tree, so they also have to set the node's parent to null if that happens.
public void insert(K key, V value) {
size++;
AVLTreeNode<K,V> newRoot = insert(super.getRoot(),key,value);
newRoot.parent = null;
super.setRoot(newRoot);
}
public void delete(K key){
AVLTreeNode<K,V> newRoot = delete(super.getRoot(), key);
if( newRoot!=null ) {
newRoot.parent = null;
}
super.setRoot(newRoot);
}
The delete method changed the key of a node, moving it out of sequence. To preserve the sequence it cannot do that.
private AVLTreeNode<K,V> delete(AVLTreeNode<K,V> root, K key) {
if (root == null) {
return root;
} else if (root.getKey().compareTo(key) > 0) {
root.setLeft(delete(root.left, key));
} else if (root.getKey().compareTo(key) < 0) {
root.setRight(delete(root.right, key));
} else {
if (root.left == null || root.right == null) {
root = (root.left == null) ? root.right : root.left;
} else {
// Promote the next node to replace root.
AVLTreeNode<K,V> mostLeftChild = minValueNode(root.right);
mostLeftChild.setRight(delete(root.right, mostLeftChild.key));
mostLeftChild.setLeft(root.left);
root = mostLeftChild;
}
if(size > 0) size--;
}
if (root != null) {
root = rebalance(root);
}
return root;
}
Then we can create an Iterator:
public static class AVLNodeIterator<K extends Comparable<K>,V> implements Iterator<AVLTreeNode<K,V>> {
AVLTree<K,V> tree;
AVLTreeNode<K,V> current;
AVLTreeNode<K,V> next;
public AVLNodeIterator(AVLTree<K,V> tree) {
this.tree = tree;
current = null;
next = tree.minValueNode(tree.getRoot());
}
#Override
public boolean hasNext() {
return next!=null;
}
#Override
public AVLTreeNode<K, V> next() {
if( next==null ) {
throw new NoSuchElementException();
}
current = next;
next = current.getNext();
return current;
}
#Override
public void remove() {
if( current==null ) {
throw new IllegalStateException();
}
tree.delete(current.getKey());
current=null;
}
}
and finally we can rewrite deleteAll to use the new iterator:
public void deleteAll(V value){
Iterator<AVLTreeNode<K,V>> iterator = new AVLNodeIterator<>(this);
while( iterator.hasNext()) {
AVLTreeNode<K,V> node = iterator.next();
if( node.getValue().equals(value) ) {
iterator.remove();
}
}
}
Related
TreeMap.java file:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TreeMap<K, V> {
private TreeNode<Pair<K, V> > root;
TreeMap() {
root = null;
}
public void delete(Pair<K, V> data) {
root = delete(root, data);
}
private static <K, V> TreeNode<Pair<K, V> > delete(TreeNode<Pair<K, V> > root, Pair<K, V> data) {
if (root == null) { // empty tree
return root;
}
if (data.compare(root.data) == 0 ) { // target on left side of tree
root.left = delete(root.left, data);
} else if (data.compare(root.data) > 0) { // target on right side of tree
root.right = delete(root.right, data);
} else if (root.left == null || root.right == null) { // root is target, but less than two children
root = root.left != null ? root.left : root.right;
} else { // root is target, but two children
root.data = getMax(root.left);
root.left = delete(root.left, root.data);
}
if (root == null) {
return root;
}
root.height = Math.max(height(root.left), height(root.right) ) + 1; // update height for balanceFactor purpose
int rootBalanceFactor = getBalanceFactor(root);
if (rootBalanceFactor > 1) { // if left subtree is unbalanced
int leftBalanceFactor = getBalanceFactor(root.left);
if (leftBalanceFactor < 0) { // make sure balanceFactor of left node >= 0
root.left = leftRotate(root.left);
}
root = rightRotate(root);
return root;
}
if (rootBalanceFactor < -1) { // if right subtree is unbalanced
int rightBalanceFactor = getBalanceFactor(root.right);
if (rightBalanceFactor > 0) { // make sure balanceFactor of right node <= 0
root.right = rightRotate(root.right);
}
root = leftRotate(root);
return root;
}
return root;
}
private Pair<K, V> getMax(TreeNode<Pair<K, V> > root) {
if (root == null) {
return null;
}
if (root.right == null) {
return root.data;
}
Pair<K, V> result = getMax(root.right);
return result;
}
public boolean search(Pair<K, V> data) {
boolean result = search(root, data);
return result;
}
private boolean search(TreeNode<Pair<K, V> > root, Pair<K, V> data) {
if (root == null) {
return false;
}
if (data.compare(root.data) < 0) {
boolean result = search(root.left, data);
return result;
}
if (data.compare(root.data) > 0) {
boolean result = search(root.right, data);
return result;
}
return true;
}
public void insert(Pair<K, V> data) {
root = insert(root, data);
}
private TreeNode<Pair<K, V> > insert(TreeNode<Pair<K, V> > root, Pair<K, V> data) {
if (root == null) { // create new node at target location
return new TreeNode<Pair<K, V> >(data);
}
if (data.compare(root.data) < 0) { // target in left subtree
root.left = insert(root.left, data);
} else if (data.compare(root.data) > 0) { // target in right subtree
root.right = insert(root.right, data);
} else { // target already exists
return root;
}
root.height = Math.max(height(root.left), height(root.right) ) + 1; // update height for balanceFactor purpose
int rootBalanceFactor = getBalanceFactor(root);
if (rootBalanceFactor > 1) { // if left subtree is unbalanced
if (data.compare(root.left.data) > 0) { // LR case
root.left = leftRotate(root.left);
}
root = rightRotate(root); // right rotation necessary in both cases
return root;
}
if (rootBalanceFactor < -1) { // if right subtree is unbalanced
if (data.compare(root.right.data) < 0) { // RL case
root.right = rightRotate(root.right);
}
root = leftRotate(root); // left rotation necessary in both cases
return root;
}
return root;
}
private int getBalanceFactor(TreeNode<Pair<K, V> > root) {
if (root == null) {
return 0;
}
int result = height(root.left) - height(root.right);
return result;
}
private int height(TreeNode<Pair<K, V> > root) {
if (root == null) {
return -1;
}
return root.height;
}
private TreeNode<Pair<K, V> > leftRotate(TreeNode<Pair<K, V> > root) {
if (root == null) {
return root;
}
if (root.right == null) {
return root;
}
TreeNode<Pair<K, V> > rightChild = root.right;
root.right = rightChild.left;
rightChild.left = root;
root.height = Math.max(height(root.left), height(root.right) ) + 1;
rightChild.height = Math.max(height(rightChild.left), height(rightChild.right) ) + 1;
return rightChild;
}
private TreeNode<Pair<K, V> > rightRotate(TreeNode<Pair<K, V> > root) {
if (root == null) {
return root;
}
if (root.left == null) {
return root;
}
TreeNode<Pair<K, V> > leftChild = root.left;
root.left = leftChild.right;
leftChild.right = root;
root.height = Math.max(height(root.left), height(root.right) ) + 1;
leftChild.height = Math.max(height(leftChild.left), height(leftChild.right) ) + 1;
return leftChild;
}
}
Pair.java file:
public class Pair<K, V> {
K key;
V value;
Pair(K key, V value) {
this.key = key;
this.value = value;
}
public int compare(Pair<K, V> pair1) {
return this.hashCode() - pair1.hashCode();
}
#Override
public int hashCode() {
return this.key.hashCode();
}
}
TreeNode.java file:
public class TreeNode<T> {
public T data;
int height;
public TreeNode<T> left, right;
public TreeNode(T data) {
this.data = data;
height = 0;
left = right = null;
}
}
I'm trying to implement a treeMap on my own in Java.
I've written the following code so far.
The methods in TreeMap.java: getMax(), height(), getBalanceFactor(), leftRotate() and rightRotate() are throwing the error: "The method getMax(TreeNode<Pair<K,V>>) in the type Tree<K,V> is not applicable for the arguments (TreeNode<Pair<K,V>>)" same with rest of the above mentioned methods with their respective parameters.
What have I done wrong? How to fix this? Thank you.
Remove the static keyword (static can't call the instance methods and cannot access the instance fields) and don't hide the generic parameters (the class definition already defines them):
From:
private static <K, V> TreeNode<Pair<K, V> > delete(TreeNode<Pair<K, V> > root, Pair<K, V> data)
To:
private TreeNode<Pair<K, V> > delete(TreeNode<Pair<K, V> > root, Pair<K, V> data)
You're getting this compilation error because you've messed around with static and instance methods.
Your method delete is defined as static and you're trying to invoke instance methods from it without the actual class instance:
root.data = getMax(root.left); // getMax() - is an instance method
...
root.height = Math.max(height(root.left), height(root.right) ) + 1; // hight() - is an instance method
...
root.left = leftRotate(root.left); // leftRotate() - is an instance method
Change the declaration of delete() to:
private TreeNode<Pair<K, V>> delete(TreeNode<Pair<K, V>> root, Pair<K, V> data)
it doesn't need to be static.
Remember, when you're invoking an instance method from another instance method, there's always an implicit reference to this:
foo(); // means this.foo() if foo() is an instance method
But if the enclosing method is static there's no implicit reference to this because static method can be invoked without creating a class instance.
I have a class MapEntry to implement Hashmap. I need to implement a method where I can get key from value and method delete. I know that HashMap does not implement such method as getValue but my prof asked to do this. I'm new to programming how it's a little bit hard for me right now. I'll appreciate any help.
public class MapEntry<K,V> {
MapEntry<K,V> next;
K key;
V value;
public MapEntry(K key, V value) {
this.setKey(key);
this.setValue(value);
}
public void setKey( K key){
this.key=key;
}
public void setValue(V value){
this.value=value;
}
public K getKey(){
return key;
}
public V getValue(){
return value;
}
public void setNext(MapEntry<K,V> next) {
this.next = next;
}
public MapEntry<K, V> getNext() {
return next;
}
}
public class HashMap{
private int DEFAULT_CAPACITY = 10;
private MapEntry<String,Double>[] Hash;
private int size;
public HashMap() {
Hash = new MapEntry[DEFAULT_CAPACITY];
}
public boolean isEmpty(){
if(size!= 0){
return false;
}
else{
return true;
}
}
public int getHashCode(String key){
int bucketIndex = key.hashCode()%Hash.length;
return bucketIndex;
}
public Double get(String key){
if(key == null){
try {
throw new IllegalAccessException("Null key");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
MapEntry<String,Double> entry = Hash[getHashCode(key)];
while (entry != null && !key.equals(entry.getKey()))
entry = entry.getNext();
if(entry != null)
return entry.getValue();
else
return null;
}
}
public void put(String key, double value){
int keyBucket =hash(key);
MapEntry<String,Double> temp = Hash[keyBucket];
while (temp !=null){
if((temp.key == null && key == null)
|| (temp.key != null && temp.key.equals(key))){
temp.value = value;
return;
}
temp = temp.next;
}
Hash[keyBucket] = new MapEntry<String, Double>(key,value);
size++;
}
public void delete (String key) throws IllegalAccessException {
if(key == null){
throw new IllegalAccessException("Null key");
}
}
private int hash(String key){
if(key == null){
return 0;
}else {
return Math.abs(key.hashCode()% this.Hash.length);
}
}
public static void main(String[] args) {
HashMap hashMap = new HashMap();
hashMap.put("value", 2.2);
hashMap.put("bob", 2.3);
System.out.println(hashMap.get("value"));
System.out.println(hashMap.get("bob"));
System.out.println(hashMap.size);
System.out.println(hashMap.getHashCode("value"));
System.out.println(hashMap.getHashCode("bob"));
System.out.println(hashMap.isEmpty());
}
}
I think the basic algo will be :
Iterate through all the values one by one
If your value matches the desired result, retrieve the key from that entry.
To delete that entry, simply remove that entry
Note : Doesn't work properly if you have multiple entries of same value.
I've just created a method to test the height of my binary tree implementation as follows:
public int height() {
return height(rootNode);
}
private int height(BinaryTreeNode node) {
if(node == null) return -1;
else return 1 + Math.max(height(node.getLeftChild()), height(node.getRightChild()));
}
But it returns a height of 6, and not 7 when i add the nodes 1-6.
Here is my Binary Tree code:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
public class BinaryTree<E extends Comparable<E>>
{
private class BinaryTreeNode
{
private E value;
private BinaryTreeNode leftChild, rightChild;
public BinaryTreeNode(E value) {
this(value, null, null);
}
public BinaryTreeNode(E value, BinaryTreeNode leftChild, BinaryTreeNode rightChild) {
this.value = value;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
public E getValue() {
return value;
}
public BinaryTreeNode getLeftChild() {
return leftChild;
}
public BinaryTreeNode getRightChild() {
return rightChild;
}
public void setLeftChild(BinaryTreeNode newLeftChild) {
this.leftChild = newLeftChild;
}
public void setRightChild(BinaryTreeNode newRightChild) {
this.rightChild = newRightChild;
}
}
private BinaryTreeNode rootNode;
public BinaryTree() {
this.rootNode = null;
}
public void addNode(E value) {
if(rootNode == null)
rootNode = new BinaryTreeNode(value);
else
addNode(value, rootNode);
}
//TODO: Implement removeNode()
public void printLevelOrder() {
printLevelOrder(rootNode);
}
public int height() {
return height(rootNode);
}
public void inOrderTraversal() {
if(rootNode != null) inOrderTraversal(rootNode);
else System.out.println("The tree is empty!");
}
private void addNode(E value, BinaryTreeNode node) {
if(node.getValue().compareTo(value) > 0) {
if(node.getLeftChild() != null)
addNode(value, node.getLeftChild());
else
node.setLeftChild(new BinaryTreeNode(value));
} else {
if(node.getRightChild() != null)
addNode(value, node.getRightChild());
else
node.setRightChild(new BinaryTreeNode(value));
}
}
private void printLevelOrder(BinaryTreeNode node) {
Queue<BinaryTreeNode> currentLevel = new LinkedList<BinaryTreeNode>();
Queue<BinaryTreeNode> nextLevel = new LinkedList<BinaryTreeNode>();
currentLevel.add(node);
while (!currentLevel.isEmpty()) {
Iterator<BinaryTreeNode> iter = currentLevel.iterator();
while (iter.hasNext()) {
BinaryTreeNode currentNode = iter.next();
if (currentNode.leftChild != null) {
nextLevel.add(currentNode.leftChild);
}
if (currentNode.rightChild != null) {
nextLevel.add(currentNode.rightChild);
}
System.out.print(currentNode.value + " ");
}
System.out.println();
currentLevel = nextLevel;
nextLevel = new LinkedList<BinaryTreeNode>();
}
}
private int height(BinaryTreeNode node) {
if(node == null) return -1;
else return 1 + Math.max(height(node.getLeftChild()), height(node.getRightChild()));
}
private void inOrderTraversal(BinaryTreeNode node) {
if(node != null) {
inOrderTraversal(node.leftChild);
System.out.println(node.getValue() + " ");
inOrderTraversal(node.getRightChild());
}
}
public BinaryTreeNode getRoot() {
return rootNode;
}
}
I think the problem is adding my node into the tree, but I've taken a look at other examples but they all seem to be doing the same thing I am.. So i can't realise the problem!
Thanks!
private int height(BinaryTreeNode node) {
if(node == null) return 0;
else return 1 + Math.max(height(node.getLeftChild()), height(node.getRightChild()));
}
You were returning -1 on node==null when you should return 0.
The condition is true when we arrive to leaf so for example if we add 1-2 then we have height as 1+Max(leftof(1),rightof(1))=
1+Max(height(null),height(2))=
1+Max(0,1+Max(leftof(2),rightof(2)))=
1+Max(0,1+Max(height(null),height(null)))=
1+Max(0,1+Max(0,0))=
1+Max(0,1+0)=
1+1=2.
Try to replace height(null) with -1 in the previous example to see by yourself.
By the way your BinaryTree implementation is actually a binary search tree since you're putting less elements on the left and bigger elements on the right, If a search tree is your intention then Ok but if you want to implement a general binary tree then you should change the add function.
Here there is code for a simple BST in Java that keys are only int, but when I want to test it and use print() just root.key can be printed and root.right and root.left are null.
public class BST {
private class Node {
private int key;
private Node left, right;
public Node(int key) {
this.key = key;
}
}
private Node root;
public BST(int key) {
root = new Node(key);
}
public void insert(int key) {
insert(root, key);
}
private void insert(Node x, int key) {
if (x == null) {
x = new Node(key);
}
if (key > x.key) {
insert(x.right, key);
} else if (key < x.key) {
insert(x.left, key);
} else {
x.key = key;
}
}
public void print() {
print(root);
}
private void print(Node x) {
System.out.print(x.key + " ");
if (x.left != null)
print(x.left);
if (x.right != null)
print(x.right);
}
}
For example, when I insert 25, 9, 10, 30, 40 and call print() then it just prints 25.
x = new Node(key);
This assignment basically throws away the new Node, because x is just a local variable. You are not modifying the callers reference here, you are just modifying the local copy of the reference the caller gave you. What you could do is return the x and have the caller assign it:
x = insert(x, 3);
The insert would then look something like this:
private Node insert(Node x, int key) {
if (x==null){
return new Node(key);
}
if (key > x.key) {
x.right = insert(x.right, key);
}else if (key < x.key) {
x.left = insert(x.left, key);
}else{
x.key = key;
}
return x;
}
I have been plugging away at a Binary Search Tree implementation for a few days now and I am to the point where I know that my root is being populated through the use of my 'insert()' (I can see this when I debug, using Eclipse). Why won't my other nodes get added to the tree?
Here is my BST Class:
package binarySearchTree;
public class BinarySearchTree<T extends Comparable<T>> {
#SuppressWarnings("hiding")
private class BinarySearchTreeNode<T>{
public BinarySearchTreeNode left, right;
private T data; //LINE 8
private BinarySearchTreeNode (T data,BinarySearchTreeNode left, BinarySearchTreeNode right ) {
this.left = left;
this.right = right;
this.data = data;
}
}
private BinarySearchTreeNode<T> root;
#SuppressWarnings("unused")
private T search(T target, BinarySearchTreeNode<T> ptr) {
//find target in subtree A ptr
if (root == null || ptr == null) {
return root; //target is not in tree
}
int compare = target.compareTo(ptr.data); //compareTo(ptr.data);
if (compare == 0) {
return ptr.data; //target is found
}
if (compare < 0) {
return search(target, ptr.left);
}
if (compare > 0) {
return search(target, ptr.right);
}
return target;
}
public T search(T target) {
return search(target);
}
public boolean isEmpty() {
return root == null;
}
/* To insert a data into a BST, 1st search for the data,
* if the data is found = duplicate data error
* if the data is NOT found = a null pointer
* Make this null pointer point to a NewNode holding data
* new values go into the BST as leaves
* Using public boolean insert (T node) &
* private boolean insert (T Node, BSTNode<T> ptr) as a recursive method
*/
#SuppressWarnings("unchecked")
private boolean insert(T value, BinarySearchTreeNode<T> ptr) {
//T data = null;
//insert data in a child of ptr, return false if duplicate is found
//Precondition: ptr must not be null
int compare = value.compareTo(ptr.data); //LINE 55
if (compare == 0) {
return false;
}
if (compare < 0) {
if (ptr.left == null) {
//found insertion point
BinarySearchTreeNode<T> node = new BinarySearchTreeNode<>(value, null, null);
ptr.left.data = node; //insert data in new node
return true;
}
} else {
return insert(value, ptr.left); //LINE 67
}
if (compare > 0) {
if (ptr.right == null) {
BinarySearchTreeNode<T> node = new BinarySearchTreeNode<>(value, null, null);
ptr.right.data = node;
return true;
} else {
return insert(value, ptr.right);
}
}
return false;
}
public boolean insert(T value) {
if (isEmpty()) {
root = new BinarySearchTreeNode<T>(value, null, null);
return true;
}
return insert(value, root); // LINE 85
}
}
And here is my Main(), eventually I would like to print the values of my BST in the console but first I know they need to be added to the tree:
package binarySearchTree;
public class Main {
public static void main(String[] args) {
BinarySearchTree<String> bstStrings = new BinarySearchTree<String>();
String s = "Hello";
String s1 = "World";
//String s2 = "This Morning";
bstStrings.insert(s);
bstStrings.insert(s1); //LINE 15
//bstStrings.insert(s2);
while (true){
if (!bstStrings.isEmpty()){
System.out.println(bstStrings + " ");
}
System.out.println();
System.out.println("You should have values above this line!");break;
}
}
}
Your root should be of BinarySearchTree<T> and not T
As a result you are not storing the values in the subtrees of the root.
Replace this:
return insert((T) value, node);
with
return insert((T) value, root);
in your code replace as follows:
public boolean insert(T value) {
if (isEmpty()) {
root = new BinarySearchTreeNode((T) value, null, null);
return true;
}
return insert((T) value, root); // start recursion
}
Otherwise you don't have a tree and the nodes are not linked to each other
UPDATE:
You get the NPE because you pass in insert the left child of root in the first comparison which is null.
You should not return boolean but BinarySearchTreeNode.
Your method should be:
#SuppressWarnings("unchecked")
private BinarySearchTreeNode<T> insert(T value, BinarySearchTreeNode<T> ptr) {
if(ptr == null){
ptr = new BinarySearchTreeNode<T>(value,null,null);
return ptr;
}
//your code next but return the `ptr`
}
Then in insert you should do:
public void insert(T value) {
root = insert(value, root);
}
After the first insertion, you create new nodes, but don't do anything with them.