Problems with Binary Tree node removal Java - java

I wanted to try and implement my own BST as an exercise, but I am stuck on the node removal. I cannot figure out why it doesn't work in some cases. I took the algorithm from a book, but when I test it with random elements, there are cases in which it does not remove the element, or even messes up their order so they are no longer sorted. What am I doing wrong and what would be a better way to accomplish this?
NOTE: All of the println() statements in the methods are there only for debugging purposes
class TreeNode<T extends Comparable<T>> {
T data;
TreeNode<T> left;
TreeNode<T> right;
TreeNode<T> parent;
TreeNode(T data) {
this.data = data;
}
boolean hasBothChildren() {
return hasLeftChild() && hasRightChild();
}
boolean hasChildren() {
return hasLeftChild() || hasRightChild();
}
boolean hasLeftChild() {
return left != null;
}
boolean hasRightChild() {
return right != null;
}
boolean isLeftChild() {
return this.parent.left == this;
}
boolean isRightChild() {
return this.parent.right == this;
}
}
public class BinaryTreeSet<T extends Comparable<T>> {
private TreeNode<T> root;
private void makeRoot(T element) {
TreeNode<T> node = new TreeNode<T>(element);
root = node;
}
private TreeNode<T> find(T element) {
TreeNode<T> marker = root;
TreeNode<T> found = null;
while (found == null && marker != null) {
int comparator = (marker.data.compareTo(element));
if (comparator > 0)
marker = marker.left;
else if (comparator < 0)
marker = marker.right;
else
found = marker;
}
return found;
}
private TreeNode<T> max(TreeNode<T> root) {
TreeNode<T> currentMax = root;
while (currentMax.hasRightChild()) {
currentMax = currentMax.right;
}
return currentMax;
}
// returns the inorder predecessor of node
private TreeNode<T> predecessor(TreeNode<T> node) {
return max(node.left);
}
// removes a given node with 0 or 1 children
private void removeNode(TreeNode<T> node) {
if (!node.hasChildren()) {
System.out.println("node with no children");
if (node.isLeftChild())
node.parent.left = null;
else
node.parent.right = null;
}
else {
System.out.println("node with 1 child");
if (node.isRightChild()) {
if (node.hasLeftChild())
node.parent.right = node.left;
else if (node.hasRightChild())
node.parent.right = node.right;
}
else if (node.isLeftChild()) {
if (node.hasLeftChild())
node.parent.left = node.left;
else if (node.hasRightChild())
node.parent.left = node.right;
}
}
node = null;
}
public BinaryTreeSet() {
root = null;
}
public void addElement(T element) {
if (root == null)
makeRoot(element);
else {
TreeNode<T> marker = root;
TreeNode<T> node = new TreeNode<T>(element);
boolean done = false;
while(!done) {
int comparator = marker.data.compareTo(element);
if (comparator > 0) {
if (marker.hasLeftChild())
marker = marker.left;
else {
marker.left = node;
done = true;
}
}
else if (comparator < 0) {
if (marker.hasRightChild())
marker = marker.right;
else {
marker.right = node;
done = true;
}
}
else
return;
node.parent = marker;
}
}
}
public boolean contains(T element) {
boolean found = (find(element) == null)? false : true;
return found;
}
public boolean removeElement(T element) {
TreeNode<T> node = find(element);
if (node == null)
return false;
// removal of a node with no children
if (!node.hasChildren()) {
if (node.isLeftChild()) {
node.parent.left = null;
}
else if (node.isRightChild()) {
node.parent.right = null;
}
}
// removal of a node with both children
else if (node.hasBothChildren()) {
TreeNode<T> pred = predecessor(node);
T temp = pred.data;
pred.data = node.data;
node.data = temp;
removeNode(pred);
}
// removal of a node with only 1 child
else {
if (node.isRightChild()) {
if (node.hasLeftChild())
node.parent.right = node.left;
else if (node.hasRightChild())
node.parent.right = node.right;
}
else if (node.isLeftChild()) {
if (node.hasLeftChild())
node.parent.left = node.left;
else if (node.hasRightChild())
node.parent.left = node.right;
}
}
node = null;
System.out.println("item removed: " + !contains(element));
return true;
}
}

please add following Method into BinaryTreeSet Class and call it,
which will show you current element list with Left/Right prefix.
boolean rootOncePrint = true;
public void printAllTree(TreeNode<T> startNode){
if(startNode == null) return;
//System.out.println(startNode.data);
if(rootOncePrint){
System.out.println("Root : " + startNode.data);
rootOncePrint = false;
}
if(startNode.hasChildren()){
if(startNode.hasLeftChild()){
printAllTree(startNode.left);
}
if(startNode.hasRightChild()){
printAllTree(startNode.right);
}
}
if(startNode != root){
T parentValue = startNode.parent.data;
T dataValue = startNode.data;
System.out.println(startNode.data + ((parentValue.compareTo(dataValue) > 0)?"L":"R"));
}
}
After Add this code, try to add/remove element into BinaryTreeSet so
you will get to know what's going on.

Found the bug that was causing me headaches. The problem was in the cases where I remove nodes with 0 or 1 child. I was not updating their parent nodes, so that messed up with the code. So, instead of, for example
if (node.hasLeftChild())
node.parent.right = node.left;
I should have written
if (node.hasLeftChild()) {
node.parent.left = node.left;
node.left.parent = node.parent;
}
in all cases where I deal with a single child. Also, I forgot to update the root, when the root is the target of the removeElement() function.
However, as it currently stands, I feel I have a lot of repetition in the code. I am yet to come up with a more elegant solution.
EDIT: There are other minor bugs as well, mainly in the isRightChild() and isLeftChild() functions, resulting in NullPointerException if the node in question does not have a parent.

Related

deleting a node from a binary search tree in java

I am making a boolean method that Deletes an element from the binary tree,
Returns true if the element is deleted successfully
, and Returns false if the element is not in the tree. The issue that I am having is that for some reason it is not deleting the node sometimes. I just want to know if I am doing anything wrong, thanks in advance.
here is my code:
public boolean delete(E e) {
BSTDelete<E> d = new BSTDelete<E>();
boolean deleted = d.delete(e, root);
if (deleted)
size -= 1;
return deleted;
}
public class BSTDelete<E extends Comparable<E>> {
public boolean delete(E e, TreeNode<E> root) {
if (root == null) {
return false;
}
if (e == root.element) {
if (root.right == null && root.left == null) {
root = null;
} else if (root.right == null) {
root = root.left;
} else if (root.left == null) {
root = root.right;
} else
root.element = minValue(root.left);
delete(root.element, root.left);
// Delete the inorder successor
} else if (e.compareTo(root.element) < 0) {
delete(e, root.left);
} else {
delete(e, root.right);
}
return true;
}
E minValue(TreeNode<E> root) {
E minv = root.element;
while (root.right != null) {
minv = root.right.element;
root = root.right;
}
return minv;
}
}
here is a test that keeps failing. The second assertEquals says that i.next() is "Beatrice" and not "Carl"
BST <String>b = new BST<String>();
b.insert("Arthur");
b.insert("Beatrice");
b.insert("Carl");
b.insert("Dagmar");
b.delete("Beatrice");
Iterator <String> i = b.iterator();
assertEquals(i.next(), "Arthur");
assertEquals(i.next(), "Carl");
assertEquals(i.next(), "Dagmar");
}
and here is my BSTInorderIterator class:
public class BSTInorderIterator<E extends Comparable<E>> implements
java.util.Iterator<E> {
int current = 0;
ArrayList<E> list = new ArrayList<E>();
private TreeNode<E> root;
public BSTInorderIterator(TreeNode<E> root) {
list = new ArrayList<E>();
inorder(root);
}
/** Inorder traversal from the root */
public void inorder() {
inorder(root);
}
/** Inorder traversal from a subtree */
public void inorder(TreeNode<E> root) {
if (root.left != null)
inorder(root.left);
list.add(root.element);
if (root.right != null)
inorder(root.right);
}
#Override
/** More elements for traversing? */
public boolean hasNext() {
return current < list.size();
}
#Override
/** Get the current element and move to the next */
public E next() {
return list.get(current++);
}
#Override
/** Remove the current element */
public void remove() {
// to do: make this work correctly
}
The delete method inside the class BSTDelete is a recursive method, however you're never returning the recursive method calls. Therefore your delete method will only ever return false when you call it with a like d.delete(e, root) where root is null.
For example even though delete(e, root.left) might return false because root.left is null your original method call will return true since you don't return the result of delete(e, root.left).
To fix this add return when you're calling the method recursively, this might only be a partial fix to your issue:
public boolean delete(E e, TreeNode<E> root) {
if (root == null) {
return false;
}
if (e == root.element) {
if (root.right == null && root.left == null) {
root = null;
} else if (root.right == null) {
root = root.left;
} else if (root.left == null) {
root = root.right;
} else
root.element = minValue(root.left);
return delete(root.element, root.left);
// Delete the inorder successor
} else if (e.compareTo(root.element) < 0) {
return delete(e, root.left);
} else {
return delete(e, root.right);
}
return true;
}

Doubly Linked List - RemoveFirst Method

I need help with following Code:
public boolean remove(Integer value) {
if (isEmpty()) {
throw new NoSuchElementException();
}
if (!isEmpty()) {
if (head == tail) {
head = tail = null;
}
} else {
}
size--;
return false;
}
And this is my task:
"removes the first occurrence of the specified value from this list"
It s a method of a Doubly Linked List.
So far I think I did correct but I am still missing the "else" part and I have no clue what to put inside...
I also have a class with a constructor and getter- and setter- methods.
Here is my node class:
public class ListElement {
private Integer value;
private ListElement next;
private ListElement prev;
public ListElement(ListElement prev, Integer value, ListElement next) {
this.value = value;
this.next = next;
this.prev = prev;
}
public Integer getValue() {
return value;
}
public ListElement getNext() {
return next;
}
public ListElement getPrev() {
return prev;
}
public void setValue(Integer value) {
this.value = value;
}
public void setNext(ListElement next) {
this.next = next;
}
public void setPrev(ListElement prev) {
this.prev = prev;
}
}
I am assuming by the function signature that you want to delete the element with the specific value. You need to find that node and remove it:
public boolean remove(Integer value) {
if (isEmpty()) {
throw new NoSuchElementException();
}
ListElement found = head;
// Try to find it
while (null != found && !found.value.equals(value)) {
found = found.next;
}
// Not found?
if (null == found) {
throw new NoSuchElementException();
}
// Found. Unlink
if (found.prev != null) found.prev.next = found.next;
else head = found.next;
if (found.next != null) found.next.prev = found.prev;
else tail = found.prev;
size--;
return true;
}
Firstly, this if should be removed as you already test for empty
if (!isEmpty()) {
if (head == tail) {
head = tail = null;
}
} else {
}
Then you can process like:
public boolean remove(Integer value) {
if (isEmpty()) {
throw new NoSuchElementException();
}
if (head == tail) {
if (head.getValue() == value) {
head = tail = null;
} else {
// Not found, return false
size--;
return false;
}
}
ListElement current = head;
while (current != null) {
if (current.getValue() == value) {
// Found
if (current.getPrev() == null) {
// current node is head node
head = current.getNext();
current.setPrev(null);
} else if (current.next() == null) {
// current node is tail node
tail = current;
current.setNext(null);
} else {
// Current node is in the middle
ListElement prev = current.getPrev();
ListElement next = current.getNext();
prev.setNext(next);
next.setPrev(prev);
}
size--;
return true;
}
}
// Not found
size--;
return false;
}

NullPointerException adding data to BST

I am implementing a BST which has 3 classes:
BST, BSTNode and Profile.
BST class
public class BST {
private static BSTNode root;
private BSTNode parent;
BST() {
root = null;
}
public void insertProfile(Profile p) {
BSTNode newNode = new BSTNode(p);
if (root == null) {
root = newNode;
} else {
BSTNode focusNode = root;
BSTNode parent = null;
int compare = focusNode.getProfile().getName().compareTo(parent.getProfile().getName());
while (true) {
parent = focusNode;
if (compare < 0) {
focusNode = focusNode.left;
if (focusNode == null) {
parent.left = newNode;
return;
} else {
focusNode = focusNode.right;
if (focusNode == null) {
parent.right = newNode;
return;
}
}
}
}
}
}
}
When I add a single entry to the BST, it seems to work fine, but then when I add two or more entries to the BST, it gives me this error:
Exception in thread "main" java.lang.NullPointerException
at BST.insertProfile(BST.java:21)
at BSTMain.main(BSTMain.java:19)
I have been trying to resolve this for many hours, if anyone could hint where I am going wrong, would be very appreciative.
It's because of this code (in BST.java, right after the else statement in insertProfile:
BSTNode parent = null;
int compare = focusNode.getProfile().getName().compareTo(parent.getProfile().getName());
What you're doing is declaring that parent is null, but then calling a method (getProfile) on it, which is what is causing the NullPointerException. You have to instantiate parent first.
Correct insert BST to balance nodes and surround nullpointers.
public static Node insert(Node root,int data) {
if(root == null){
Node node = new Node(data);
root = node;
}else if (data > root.data) {
root.right = insert(root.right , data);
}else if (data < root.data){
root.left = insert(root.left , data);
}
return root;
}

How to get the first element when going through a binary search tree with inorder?

My try (gave me a NullPointerException):
public Karte giveFirst(BinarySearchTree<Karte> t){
if(t.getLeftTree() != null) {
return giveFirst(t.getLeftTree());
}else{
return t.getContent();
}
}
Complete Binary Search Tree Code:
package Model;
private class BSTNode<CT extends ComparableContent<CT>> {
private CT content;
private BinarySearchTree<CT> left, right;
public BSTNode(CT pContent) {
this.content = pContent;
left = new BinarySearchTree<CT>();
right = new BinarySearchTree<CT>();
}
}
private BSTNode<ContentType> node;
public BinarySearchTree() {
this.node = null;
}
public void insert(ContentType pContent) {
if (pContent != null) {
if (isEmpty()) {
this.node = new BSTNode<ContentType>(pContent);
} else if (pContent.isLess(this.node.content)) {
this.node.left.insert(pContent);
} else if(pContent.isGreater(this.node.content)) {
this.node.right.insert(pContent);
}
}
}
public BinarySearchTree<ContentType> getLeftTree() {
if (this.isEmpty()) {
return null;
} else {
return this.node.left;
}
}
public ContentType getContent() {
if (this.isEmpty()) {
return null;
} else {
return this.node.content;
}
}
public BinarySearchTree<ContentType> getRightTree() {
if (this.isEmpty()) {
return null;
} else {
return this.node.right;
}
}
public void remove(ContentType pContent) {
if (isEmpty()) {
return;
}
if (pContent.isLess(node.content)) {
node.left.remove(pContent);
} else if (pContent.isGreater(node.content)) {
node.right.remove(pContent);
} else {
if (node.left.isEmpty()) {
if (node.right.isEmpty()) {
node = null;
} else {
node = getNodeOfRightSuccessor();
}
} else if (node.right.isEmpty()) {
node = getNodeOfLeftSuccessor();
} else {
if (getNodeOfRightSuccessor().left.isEmpty()) {
node.content = getNodeOfRightSuccessor().content;
node.right = getNodeOfRightSuccessor().right;
} else {
BinarySearchTree<ContentType> previous = node.right
.ancestorOfSmallRight();
BinarySearchTree<ContentType> smallest = previous.node.left;
this.node.content = smallest.node.content;
previous.remove(smallest.node.content);
}
}
}
}
public ContentType search(ContentType pContent) {
if (this.isEmpty() || pContent == null) {
return null;
} else {
ContentType content = this.getContent();
if (pContent.isLess(content)) {
return this.getLeftTree().search(pContent);
} else if (pContent.isGreater(content)) {
return this.getRightTree().search(pContent);
} else if (pContent.isEqual(content)) {
return content;
} else {
return null;
}
}
}
private BinarySearchTree<ContentType> ancestorOfSmallRight() {
if (getNodeOfLeftSuccessor().left.isEmpty()) {
return this;
} else {
return node.left.ancestorOfSmallRight();
}
}
private BSTNode<ContentType> getNodeOfLeftSuccessor() {
return node.left.node;
}
private BSTNode<ContentType> getNodeOfRightSuccessor() {
return node.right.node;
}
}
How can I change/rewrite my code for it to work?
Think what would happen when you reach the left most leaf node.
Its left tree will be null which means you will break out of the while loop. You are returning null after this and so any attempt to access the state of the return value will throw an exception.
You must return this node when it has no more left children as that will be the smallest element in the tree
Also, I don't know why you have BinarySearchTree and BSTNode. A BSTNode should be good enough to construct a tree. Please go through some tutorial/lessons for a better understanding.
How to get the first element when going through a binary search tree with inorder?
Keep going left till you can't go left anymore... If a node has a left child, go for it. Keep doing this till you get to a node that does not have a left child. When you are there, you know you are in the left-most part of the tree. Following code snippet shows an idea of how this can be achieved given the root of a BST.
public BSTNode getSmallest(BSTNode root) {
if(root.left != null)
return getSmallest(root.left);
return root;
}

Difficulties with Binary Search Tree with Generics Implementation

I'm having an issue with implementing this BinarySearchTree listed below. For some context, I'm creating a binary search tree based off of an interface that requires generics and a comparable key.I think that there is a logic error in the code that is stumping me and it's in the insert method in the BinarySearchTree, but I'm not 100% sure.
Below is the class for my Node, which is used in my BST.
public class MyNodeClass<Key extends Comparable<Key>, Value>{
private Key key;
private Value value;
private MyNodeClass<Key,Value> left = null;
private MyNodeClass<Key,Value> right = null;
public MyNodeClass(Key key, Value val)
{
this.key = key;
this.value = val;
}
public void setKey(Key key){
this.key = key;
}
public void setValue(Value value){
this.value = value;
}
public Key getKey(){
return this.key;
}
public Value getValue(){
return this.value;
}
public void setLeft(MyNodeClass<Key, Value> l){
this.left = l;
}
public void setRight(MyNodeClass<Key, Value> r){
this.right = r;
}
public MyNodeClass<Key,Value> getLeft(){return this.left;}
public MyNodeClass<Key,Value> getRight(){return this.right;}
public int compareTo(Key that){
return(this.getKey().compareTo(that));
}
}
public class MyBinarySearchTree<Key extends Comparable<Key>, Value> implements BinarySearchTree<Key,Value> {
private MyNodeClass<Key, Value> root;
public MyBinarySearchTree(){
root = null;
}
#Override
public boolean isEmpty() {
return root == null;
}
#Override
public Value insert(Key key, Value val) {
MyNodeClass<Key,Value> newNode = new MyNodeClass<Key,Value>(key,val);
newNode.setKey(key);
newNode.setValue(val);
if(root==null){
root = newNode;
return(newNode.getValue());
}
else{
MyNodeClass<Key,Value> current = newNode;
MyNodeClass<Key,Value> parent;
while(true){
{
parent = current;
if(current.compareTo(key) == 1)
{
current = current.getLeft();
if(current == null)
{
parent.setLeft(newNode);
return parent.getLeft().getValue();
}
}
else if(current.compareTo(key) == -1){
current = current.getRight();
if(current == null)
{
parent.setRight(newNode);
return parent.getRight().getValue();
}
}
else{
if(current.compareTo(key) == 0){
current.setKey(key);
current.setValue(val);
return current.getValue();
}
}
}
}
}
}
#Override
public Value find(Key key) {
MyNodeClass<Key, Value> current = root;
while (current.compareTo(key) != 0)
{
if (current.compareTo(key) == 1)
{
current = current.getLeft();
} else {
current = current.getRight();
}
if(current == null)
return null;
}
return current.getValue();
}
#Override
public Value delete(Key key) {
MyNodeClass<Key,Value> current = root;
MyNodeClass<Key,Value> parent = root;
boolean isLeftChild = true;
while(current.compareTo(key) != 0) {
parent = current;
if (current.compareTo(key) == 1) {
isLeftChild = true;
current = current.getLeft();
} else {
isLeftChild = false;
current = current.getRight();
}
if(current == null)
return null;
}
if(current.getLeft() == null && current.getRight() == null) {
if (current == root) {
root = null;
} else if (isLeftChild) {
parent.setLeft(null);
} else{
parent.setRight(null);
}
return current.getValue();
}
else if(current.getRight() == null)
{
if(current == root) {
root = current.getLeft();
}
else if(isLeftChild) {
parent.setLeft(current.getLeft());
}
else{
parent.setRight(current.getLeft());
}
return current.getValue();
}
else if(current.getLeft() == null)
{
if(current == root)
root = current.getRight();
else if(isLeftChild)
parent.setLeft(current.getRight());
else
parent.setRight(current.getRight());
return current.getValue();
}
else
{
MyNodeClass<Key,Value> successor = getSuccessor(current);
if(current == root)
root = successor;
else if(isLeftChild)
parent.setLeft(successor);
else
parent.setRight(successor);
successor.setLeft(current.getLeft());
return current.getValue();
}
}
#Override
public String stringLevelOrder() {
return(LevelOrder(root));
}
private MyNodeClass<Key,Value> getSuccessor(MyNodeClass<Key,Value> deleteNode)
{
MyNodeClass<Key,Value> successorParent = deleteNode;
MyNodeClass<Key,Value> successor = deleteNode;
MyNodeClass<Key,Value> current = deleteNode.getRight();
while(current != null)
{
successorParent = successor;
successor = current;
current = current.getLeft();
}
if(successor != deleteNode.getRight())
{
successorParent.setLeft(successor.getRight());
successor.setRight(deleteNode.getRight());
}
return successor;
}
public static void main(String[] args)
{
MyBinarySearchTree<Double, MyStudent> BST = new MyBinarySearchTree<Double, MyStudent>();
MyStudent myStud1 = new MyStudent();
MyStudent myStud2 = new MyStudent();
MyStudent myStud3 = new MyStudent();
MyStudent myStud4 = new MyStudent();
MyStudent myStud5 = new MyStudent();
myStud1.init("Clarise", 1.1);
myStud2.init("Christopher", 1.2);
myStud3.init("John", 1.3);
myStud4.init("Chloe", 1.4);
myStud5.init("Goo", 1.5);
System.out.println(BST.insert(myStud1.getGPA(), myStud1));
System.out.println(BST.insert(myStud2.getGPA(), myStud2));
System.out.println(BST.insert(myStud3.getGPA(), myStud3));
System.out.println(BST.insert(myStud4.getGPA(), myStud4));
System.out.println(BST.insert(myStud5.getGPA(), myStud5));
System.out.println("Delete Key 1.0: " +BST.delete(1.3));
System.out.println("Delete Key 1.4: " +BST.delete(1.4));
System.out.println("Is Empty?: " +BST.isEmpty());
System.out.print("Find 3.9: "+ BST.find(3.9));
}
}
The result of the main is the following:
{Clarise:1.1}
{Christopher:1.2}
{John:1.3}
{Chloe:1.4}
{Goo:1.5}
Delete Key 1.0: null
Delete Key 1.4 null
Is Empty?: false
Find 3.9: null
I'm not entirely sure what the issue is and I've had some help from others, however they can't find the problem. Hoping that someone else can see something that we don't see.
In your insert method, after you've checked that root is not null, you are inserting newNode into the newNode instead of inserting it into the root.
This:
MyNodeClass<Key,Value> current = newNode;
MyNodeClass<Key,Value> parent;
Should be:
MyNodeClass<Key,Value> current = root;
MyNodeClass<Key,Value> parent;
P.S. any kind of testing would show you the problem with your insert within a minute. You could write a size() method and see that your inserts are not working, you could write a toString() method and see the state of the tree, finally you could debug.
MyNodeClass<Key,Value> current = newNode;
There is problem here.
If a tree is not empty, then your "current" should begin at root node. What you done is insert "newNode" to "newNode".
Change the code to be:
MyNodeClass<Key,Value> current = root;

Categories