java Delete a Binary Tree node containing two children - java

This is the last case where the node to be deleted has two children. I cant figure out what I am doing wrong . Please help.
//BTNode has two children
else if (u.getLeft() != null && u.getRight() != null){
//if node to delete is root
BTNode<MyEntry<K,V>> pred = u.getRight();
while (pred.getLeft().element() != null){
pred = pred.getLeft();
}
BTNode<MyEntry<K,V>> predParent = pred.getParent();
if (!hasRightChild(pred)){
predParent.setLeft(new BTNode<MyEntry<K,V>>(null,predParent,null,null));}
if (hasRightChild(pred)){
BTNode<MyEntry<K,V>> predChild = pred.getRight();
predParent.setLeft(predChild);
predChild.setParent(predParent);
}
return returnValue;
ok so modify it like this ??
u.setElement(succ.element());
BTNode<MyEntry<K,V>> succParent = succ.getParent();
if (!hasLeftChild(succ)){
succParent.setRight(new BTNode<MyEntry<K,V>>(null,succParent,null,null));}
if (hasLeftChild(succ)){
BTNode<MyEntry<K,V>> predChild = succ.getLeft();
succParent.setRight(predChild);
predChild.setParent(succParent);
}
return returnValue;

From wikipedia:
Deleting a node with two children: Call the node to be deleted N. Do
not delete N. Instead, choose either its in-order successor node or
its in-order predecessor node, R. Replace the value of N with the
value of R, then delete R.
So, take for example the left children, and then find the rightmost leaf in that subtree, then replace the information of the node to delete with that of the leaf, and then delete that leaf easily.
You might want to create a function that returns the rightmost leaf from a subtree.

I have given the code for deletion of a node in a BST which would work for any condition and that too using a for loop.
public void delete(int key) {
Node<E> temp = find(key);
System.out.println(temp.key);
for (;;) {
// case 1 : external node
if (temp.isExternal()) {
if (temp.getParent().getrChild() == temp) {
temp.parent.rightchild = null;
temp = null;
} else {
temp = null;
}
break;
}
// case2 : one child is null
else if ((temp.getlChild() == null) || (temp.getrChild() == null)) {
if ((temp.parent.leftchild != null) && temp.getParent().getlChild().key == temp.key) {
if (temp.getlChild() == null) {
temp.getParent().setLeft(temp.getrChild());
temp.getrChild().setParent(temp.getParent());
break;
}
else
temp.getParent().setLeft(temp.getlChild());
temp.getlChild().setParent(temp.getParent());
}
else {
if (temp.rightchild != null) {
System.out.println("in");
temp.getParent().setRight(temp.getrChild());
temp.getrChild().setParent(temp.getParent());
break;
}
else
temp.getParent().setRight(temp.getlChild());
temp.getlChild().setParent(temp.getParent());
}
break;
}
// case 3 : has both the children
else {
int t = temp.key;
temp.key = temp.getlChild().key;
temp.getlChild().key = t;
temp = temp.getlChild();
continue;
}
}
}

Related

Deleting a node in a Binary Search Tree using Java

Could you tell me why this code wont delete a node in a BST? Is there any logical error in my code?
// To delete a node from the BST
public Node deleteNode(Node myRoot, int toDel) {
if (myRoot == null) return null;
else if (toDel < myRoot.data) myRoot.left = deleteNode(myRoot.left, toDel);
else if (toDel > myRoot.data) myRoot.right = deleteNode(myRoot.right, toDel);
else {
// Leaf node
if (myRoot.right == null && myRoot.left == null) {
myRoot = null;
} else if (myRoot.left == null) { // No left child
myRoot = myRoot.right;
} else if (myRoot.right==null){ // No right child
myRoot = myRoot.left;
}
}
return myRoot;
}
NOTE :- This code only deletes the nodes with one child or no child. I am currently working on deleting a node with 2 children so please dont solve that for me.
If 0 children, simply delete node (return null for it).
If there is 1 child, simply replace the node with the child that is not null.
public Node deleteNode(Node myRoot, int toDel) {
if (myRoot == null) {
return null;
} else if (myRoot.data == toDel) {
if (myRoot.left != null) {
return myRoot.left;
} else if (myRoot.right != null) {
return myRoot.right;
} else {
return null;
}
}
...
return myRoot;
}

Implementing a linked list in Java (Finding/Deleting Nodes)

I've been working on some code to implement an (edit: unidirectional) linked list in java. My main issue is coming about when it comes to finding and deleting nodes, that is, using Find(data) tells the user whether or not a node is present in the list; Delete(data) actually removes the node from the list after it is found (or does nothing if the node isn't found). Find(data) and Delete(data) use the same if-else logic, so for right now I just copied the code from the Find method into the delete method, with appropriate pointers in the delete method to "hop over" the deleted node.
I'm wondering if there's a more efficient way of doing this. I thought of using booleans in the delete block, for example:
public void Delete(data)
{
if Find(data)
{
//code to delete node
}
}
but because the current node could be at the head, tail, or somewhere in the middle, you'd still have to have the loop logic to check where you are so you can set the appropriate references. For example, if the user wants to delete the node at the tail, then the previous node's next node would be set to null. However, in the middle, you'd have to run a while loop to iterate through the list, i.e.
while (iter.NextNode !=null)
{
if (iter.NextNode.data == data)
{
iter.NextNode = iter.NextNode.NextNode;
System.out.println(data + " was found in the list and removed"
break;
}
else if (iter.NextNode.NextNode == null && iter.NextNode.data == data)
{//this is kinda weird. I couldn't use an else block, because either
//the code would never exit the loop, or it would keep running
iter.NextNode = null;
System.out.println(data + " was found in the list and removed. ");
break;
}
iter = iter.NextNode;
if (node.NextNode == null && node.data != data)
{//i guess I could have just put this if statement inside
//the else block
System.out.println(data + " was not found in the list.");
break;
}
}
The above code block handles both cases.
The below code block is my Find(data) method:
public void Find(int data)
{
Node node = head;
if (head == null)
{
System.out.println("No nodes found. ");
}
else if (node.NextNode==null)
{
if (node.data == data)
{
System.out.println( data + " was found in the list.");
}
else
{
System.out.println("That value was not found in the list.");
}
}
else
{
while (node.NextNode !=null)
{
if (node.data == data)
{
System.out.println(data + " was found in the list.");
break;
}
else if (node.NextNode.NextNode == null && node.NextNode.data == data)
{
System.out.println(data + " was found in the list.");
break;
}
else
{
node = node.NextNode;
}
if (node.NextNode == null && node.data != data)
{
System.out.println(data + " was not found in the list.");
break;
}
}
}
}
In case the question wasn't clear: Is there a way I can use my Find(data) method in the delete block, and take out all the logic?
Thanks for your guidance. I really appreciate it!
As your Find() method returns nothing, you can not use it in a Delete() method.
To Centralize your code for Find() and Delete() create another private method - getPreviousNode(int data) which returns previous node of a required node.
private Node getPreviousNode(int data) {
Node iter = head;
while (iter.NextNode != null) {
if (iter.NextNode.data == data) {
return iter;
}
iter.nextNode = iter.nextNode.nextNode;
}
return null;
}
Call this method in both Find() and Delete() method.
void Find(int data) {
// Code to handle head & tail conditions
Node prevNode = getPreviousNode(data);
if (prevNode != null) {
System.out.println("Found");
}
...
}
void Delete(int data) {
// Code to handle head & tail conditions
Node prevNode = getPreviousNode(data);
if (prevNode != null) {
Node node = prevNode.nextNode;
prevNode.nextNode = node.nextNode;
node.nextNode = null;
System.out.println("Found & Deleted");
}
...
}
Answer to your comment:
Writing just "prevNode.nextNode = prevNode.NextNode.NextNode" is not sufficient.
Consider Following LinkedList:
A[data = 1 | nextNode = b] --> B[data = 4 | nextNode = c] --> C[data = 55 | nextNode = null]
where,
A, B, C : Nodes
a, b, c : References to Nodes A, B and C respectively.
B : Node to delete
Now consider a code to delete node:
Node prevNode = getPreviousNode(data);
prevNode = a; // "a" is a reference to Node A returned by getPreviousNode(4)
if (prevNode != null)
node = prevNode.nextNode;
node = b; // prevNode.nextNode is 'b'
prevNode.nextNode = node.nextNode;
prev.NextNode = c; // node.nextNode is 'c'
Now LinkedList is:
A[data = 1 | nextNode = c] B[data = 4 | nextNode = c] --> C[data = 55 | nextNode = null]
Now node A has a reference of Node C as a nextNode. So Node B is unlinked from LinkedList
but not completely removed from LinkedList because Node B is still having reference of Node C
as a NextNode. So you must remove this reference to remove Node B completely from LinkedList.
So following statement is neccessary
node.nextNode = null;
Now LinkedList is:
A[data = 1 | nextNode = c] --> C[data = 55 | nextNode = null]
B[data = 4 | nextNode = null] is removed from LinkedList.
You could share findPrevious as #SanjayChavan suggests, but when you are practiced at writing linked list code, you find that it's already clean and sharing findPrevious doesn't make it better:
boolean Delete(int data)
{
Node prev = null, node = null;
for (node = head; node!=null; node=(prev=node).nextNode)
{
if (node.data == data)
{
if (prev!=null)
prev.nextNode = node.nextNode;
else
head = node.nextNode;
node.nextNode = null;
return true;
}
}
return false;
}
Node Find(int data)
{
for (Node node = head; node != null; node = node.nextNode)
{
if (node.data==data)
return node;
}
return null;
}
Once Sanjay's code is fixed so that it can find and delete the head node, it will be longer and more complicated than this.
public static ListNode search( List list, int target )
{
ListNode cursor = list.getFirst( );
while( cursor != null )
{
if( cursor.getInfo( ) == target )
return cursor;
cursor = cursor.getLink( );
}
return cursor;
}
public void remove( int element )
{
ListNode cursor;
ListNode target = search( this, element );
if( isEmpty( ) )
System.out.println( "There are no elements in this list." );
if( target == null )
System.out.println( element+" is not in this list." );
else
{
if( head.getInfo( ) == element )
{
if( head.getLink( ) == null )
head = null;
else if( head == tail )
tail = null;
else
head = head.getLink( );
}
else if( tail.getInfo( ) == element )
{
for( cursor = head; cursor.getLink( ).getInfo( ) != element; cursor = cursor.getLink( ) )
{ }
cursor.setLink( null );
tail = cursor;
}
else
{
for( cursor = head; cursor.getLink( ).getInfo( ) != element; cursor = cursor.getLink( ) )
{ }
cursor.setLink( cursor.getLink( ).getLink( ) );
}
}
}

Getting an object from a recursive deletion Java

I have a Binary Search Tree that contains nodes. Each node contains a key value and data value, and the nodes are sorted by key. I am trying to write a method to remove an object from my BST provided a key. Here is the code:
public Object remove(Comparable theKey) {
return remove(theKey, rootPtr).data;
}
public Node remove(Comparable theKey, Node node) {
Object o;
if(node == null)
return node;
if(theKey.compareTo(node.key) < 0) {
// go to left subtree
node.leftChild = remove(theKey, node.leftChild);
}else if(theKey.compareTo(node.key) > 0) {
//go to the right subtree
node.rightChild = remove(theKey, node.rightChild);
}else if(theKey.compareTo(node.key) == 0) {
if(node.leftChild != null && node.rightChild != null){
Node foundNode = findMin(node.rightChild);
node.key = foundNode.key;
node.data = foundNode.data;
node.rightChild = remove(node.key, node.rightChild);
}else{
if(node.leftChild != null){
node = node.leftChild;
}else{
node = node.rightChild;
}
}
}
numNodes--;
return node;
}
I would like to return the data value associated with the DELETED node. The issue I have is that: in the public Object remove() method, wouldn't the returned value always be the data value of the root node? I believe this would occur because the final returned call from the second method would be a reference to the rootPtr (root pointer). If this is the case, how can I save the data from the deleted node?
The simplest solution seems to be to add an output parameter than hands back the result:
public Object remove(Comparable theKey) {
Object[] result = new Object[1];
rootPtr = remove(theKey, rootPtr, result); // fix for deletion from a one-node tree
return result[0];
}
public Node remove(Comparable theKey, Node node, Object[] result) {
if(node == null) {
return node;
}
int diff = theKey.compareTo(node.key);
if (diff < 0) {
node.leftChild = remove(theKey, node.leftChild, result);
} else if (diff > 0) {
node.rightChild = remove(theKey, node.rightChild, result);
} else {
result[0] = node.key;
if (node.rightChild == null) {
node = node.leftChild;
} else if (node.leftChild == null) {
node = node.rightChild;
} else {
Node foundNode = findMin(node.rightChild);
node.key = foundNode.key;
node.data = foundNode.data;
node.rightChild = remove(node.key, node.rightChild, new Object[1]);
}
numNodes--;
}
return node;
}
Returning the found node doesn't work without significant changes because the return parameter is used to replace nodes as needed, and in the case where the found node has two children, you'd need to make a copy or insert a new node. Handling the case where the root node gets removed would be an issue, too.
p.s. I am assuming this is not a "trick question" and you can't just return theKey -- which has to equal the found key after all :)
You have to return the value, that you are receiving from the recursive remove-call.
p.ex:
if(theKey.compareTo(node.key) < 0) {
// go to left subtree
return remove(theKey, node.leftChild);
}else if ...
Now you will run throught the tree, until you find the correct node and that node will be given to the node which is the parent of the node to remove, and the parent will than give it to his parent and so on, until the root will return the node to his caller.

Deleting Value in Binary Tree

I have a slightly working binary search tree delete value function. The only time that it does not work is if you are trying to delete a root that has two children.
public boolean delete(BinaryTreeNode node, int i){
if (node == null){
return false;
} else {
if (node.getKey() == i){
BinaryTreeNode parent = new BinaryTreeNode(0, null, null);
parent.setLeftChild(root);
boolean result = deleteHelper(i, node, parent);
root = parent.getLeftChild();
return result;
} else {
return deleteHelper(i, node, null);
}
}
}
public boolean deleteHelper(int value, BinaryTreeNode curr, BinaryTreeNode parent){
if (value < curr.getKey()){
if (curr.getLeftChild() != null){
return deleteHelper(value, curr.getLeftChild(), curr);
} else {
return false;
}
} else if (value > curr.getKey()){
if (curr.getRightChild() != null){
return deleteHelper(value, curr.getRightChild(), curr);
} else {
return false;
}
} else {
if (curr.getRightChild() != null && curr.getLeftChild() != null){
curr.setKey(findMin(curr.getRightChild()).getKey());
deleteHelper(curr.getKey(), curr.getRightChild(), curr);
} else if (parent.getLeftChild() == curr){
parent.setLeftChild((curr.getLeftChild() != null)?curr.getLeftChild():curr.getRightChild());
} else if (parent.getRightChild() == curr){
parent.setRightChild((curr.getLeftChild() != null)?curr.getLeftChild():curr.getRightChild());
}
return true;
}
}
According to Wikipedia
Deleting a node with two children: Call the node to be deleted N. Do not delete N. Instead, choose either its in-order successor node or its in-order predecessor node, R. Copy the value of R to N, then recursively call delete on R until reaching one of the first two cases.
http://en.wikipedia.org/wiki/Binary_search_tree#Deletion
You can try by successor node as follows:
get successor of node to delete (current)
connect parent of current to successor
connect successor to the left child for current
For more details check out this link
Java, Binary tree remove method

Balancing check never terminates in Avl tree insertion

Writing an AVL Tree to hold generics for my data structures course; in my add() method, after actually inserting an element, I step back up through its ancestors checking their scores. For the first few additions it works, but (presumably at the point where balancing does need to be done), the loop back up the path fails to terminate. I've tried everything I can think of to make sure the root of the tree's parent isn't getting set to another node or anything like that. I'm calculating balance scores as right minus left, so positive means a tree is right-heavy and negative means left-heavy. Here's my add():
public void add(T e){
if (e == null)
return;
if (root == null) {
root = new TNode<T>(null, e);
return;
}
boolean added = false;
TNode<T> current = root;
while (current != null && added != true) { //insertion loop
if (current.compareTo(e) == 0)
return;
else if (current.compareTo(e) < 0) {
if (current.getRight() == null) {
current.setRight(new TNode<T>(current, e));
added = true;
}
else
current = current.getRight();
}
else if (current.compareTo(e) > 0) {
if (current.getLeft() == null) {
current.setLeft(new TNode<T>(current, e));
added = true;
}
else
current = current.getLeft();
}
}
if (useAVL == false)
return;
//balancing, checking up from added node to find where tree is unbalanced; currently loop does not terminate
//current is now parent of inserted node
while (current.hasParent()) {
if (current.getAvl() > 1) {
if (current.getRight().getAvl() > 0)
current = rotateLeft(current);
else if (current.getRight().getAvl() < 0) {
current.setRight(rotateRight(current.getRight()));
current = rotateLeft(current);
}
}
if (current.getAvl() < -1) {
if (current.getLeft().getAvl() < 0)
current = rotateRight(current);
else if (current.getLeft().getAvl() > 0) {
current.setLeft(rotateLeft(current.getLeft()));
current = rotateRight(current);
}
}
current = current.getParent();
}
root = current;
root.setParent(null);
}
And here's the right rotation method:
private TNode<T> rotateRight(TNode<T> old) {
TNode<T> oldRoot = old;
TNode<T> newRoot = old.getLeft();
TNode<T> rightChildNewRoot = newRoot.getRight(); //was right child of what will become root, becomes left child of old root
newRoot.setRight(oldRoot);
oldRoot.setParent(newRoot);
oldRoot.setLeft(rightChildNewRoot);
if (rightChildNewRoot != null)
rightChildNewRoot.setParent(oldRoot);
newRoot.setParent(oldRoot.getParent());
return newRoot;
}

Categories