I'm trying to remove the root of my binary search tree so I can update it's value, but this method can't do it. My idea is to remove the root, and then insert it again in the binary search tree but with another value. It works with every Node in the tree, but not the root cause I cannot delete it. Anyone knows why this happens? Thanks.
public V remove(K key) {
Node node = remove(key, root);
return node.value;
}
private Node remove(K key, Node current) {
if (current == null) {
return null;
}
if (current.key.equals(key)) {
if (current.left == null && current.right == null) {
return null;
}
else if (current.left == null && current.right != null) {
return current.right;
} else if (current.left != null && current.right == null) {
return current.left;
} else {
Node plowest = current.right;
Node parent = current;
while (plowest.left != null) {
parent = plowest;
plowest = plowest.left;
}
plowest.left = current.left;
if (plowest != current.right) {
parent.left = plowest.right;
plowest.right = current.right;
}
return plowest;
}
}
if (key.compareTo(current.key) < 0) { // Subarbre esquerra
current.left = remove(key, current.left);
} else {// Subarbre dret
current.right = remove(key, current.right);
}
return current;
}
And this is the main code where I call the method to delete any Node, in this case I would like to delete the root.
public static void main(String[] args) {
BSTMapping<String, Integer> arbre = new BSTMapping();
arbre.put("G", 4);
arbre.put("A", 1);
arbre.put("C", 2);
arbre.remove("G");
Iterator it = arbre.iterator();
while (it.hasNext()) {
BSTMapping.Pair p = (BSTMapping.Pair) it.next();
System.out.println(p.getKey() + " - " + p.getValue());
}
}
When removing root, remove(K key, Node current) never reaches the bottom where it would assign a node to current.left or current.right. You can address this in remove(key) by assigning directly to the root variable when appropriate.
public V remove(K key) {
Node node = remove(key, root);
if (root.key.equals(key)) {
root=node;
}
return node.value;
}
Related
This removes almost all of what is supposed to, except for the last item.
This is what I get back when I submit it:
Input: [thing, word, stuff, and, both, zoo, yes]
----------Expected size: 0 BST actual number of nodes: 1
Invalid tree after removing thing
Code Below:
#SuppressWarnings("unchecked")
public boolean remove(Object o) {
Node n = root;
while (n != null) {
int comp = n.value.compareTo(o);
if (comp == 0) {
size--;
remove(n);
return true;
} else if (comp > 0) {
n = n.left;
} else {
n = n.right;
}
}
return false;
}
private void remove(Node root) {
if (root.left == null && root.right == null) {
if (root.parent == null) {
root = null;
} else {
if (root.parent.left == root) {
root.parent.left = null;
} else {
root.parent.right = null;
}
}
} else if (root.left == null || root.right == null) {
Node child = root.left;
if (root.left == null) {
child = root.right;
}
if (root.parent == null) {
root = child;
} else if (root.parent.left == root) {
root.parent.left = child;
} else {
root.parent.right = child;
}
child.parent = root.parent;
} else {
Node successor = root.right;
if (successor.left == null) {
root.value = successor.value;
root.right = successor.right;
if (successor.right != null) {
successor.right.parent = root;
}
} else {
while (successor.left != null) {
successor = successor.left;
}
root.value = successor.value;
successor.parent.left = successor.right;
if (successor.right != null) {
successor.right.parent = successor.parent;
}
}
}
}
Removal of a node in a Binary-search-tree consists of the following steps:
Find the node
You need to make sure that you have a function which is used for searching in order to find the node to be removed.
Handle the node's subtree
If the node has less than two children, then the subtree can be trivially changed. If there is a child, then the current node will be replaced by its child. Otherwise, if there are two children of the node to be removed, then you will just need to replace the node to be removed with the rightmost node of the left subtree or the leftmost node of the right subtree of the element to be removed.
Ensure that if you have replaced your current node with something else, then the other node will not exist as a duplicate.
In order to achieve this you will need methods like:
- search
- find leftmost/rightmost node of subtree
- remove
Your current code is over-complicated. I would rewrite it using atomic methods.
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;
}
I'm writing a code for implementing BST in java. My insert, search, search for inorder successor, inorder traversal work fine but when I remove a node, it is not actually removed. Consider the simplest case where the node to be removed is a pendant node. Even if I set this node to null, it is still printed in inorder traversal after deletion. Can anyone please help? Thank you.
package pack_l;
class BSTNode
{
int key;
BSTNode left;
BSTNode right;
BSTNode(int key)
{
this.key = key;
this.left = this.right = null;
}
}
class BST
{
BSTNode root;
BST()
{
root = null;
}
/*insert a node at proper position*/
void insert(BSTNode n)
{
if(root == null)
root = n;
else
{
BSTNode node = root;
while(node != null)
{
if(node.key > n.key)
{
if(node.left == null)
{
node.left = n;
return;
}
else
node = node.left;
}
else
{
if(node.right == null)
{
node.right = n;
return;
}
else
node = node.right;
}
}/*End of while-loop*/
}
}
/*Search a node in the whole tree*/
BSTNode search(int val)
{
BSTNode node = root;
while(node != null)
{
if(node.key == val)
return node;
else if(node.key > val)
node = node.left;
else
node = node.right;
}
return null;
}
/*Remove a node from the tree*/
boolean remove(int val)
{
BSTNode delNode = search(val);
/*If the node is not in the BST*/
if(delNode == null)
return false;
/*If the node has no child*/
if(delNode.left == null && delNode.right == null)
delNode = null;
return true;
}
void inorder(BSTNode root)
{
if(root == null)
return;
inorder(root.left);
System.out.print(" " + root.key + " ");
inorder(root.right);
}
}
public class BSTree {
public static void main(String[] args) {
BST tree = new BST();
BSTNode n1 = new BSTNode(15);
tree.insert(n1);
System.out.println("Before:");
tree.inorder(tree.root);
tree.remove(15);
System.out.println("\nAfter:");
tree.inorder(tree.root);
}
}
Setting delnode = null does nothing: you have a local copy of the reference to a node, and you changed it to refer to null. That doesn't change the actual node in memory at all.
Instead, you must find its parent and set that parent's left or right reference (depending on which is the node to delete) to null.
hi i build this code for BST:
public class BinarySearchTreeCode {
private class BSTNode {
public Object data;
public BSTNode left;
public BSTNode right;
BSTNode(Object newdata) {
data = newdata;
left = null;
right = null;
}
BSTNode(Object data, BSTNode left, BSTNode right){
this.data = data;
this.left = left;
this.right = right;
}
public String toString(){
return "data: "+data+" ";
}
}
// tree root
private BSTNode root;
public BinarySearchTreeCode(){
root = null;
}
public BinarySearchTreeCode(BSTNode n){
root = n;
}
public BinarySearchTreeCode(BinarySearchTreeCode bst){// copy constructor
this.root = clone(bst.root);
}
BSTNode clone(final BSTNode source){
if (source == null) return null;
else
return new BSTNode(source.data, clone(source.left), clone(source.right));
}
// compare two objects (integer type)
private static int compare(Object o1, Object o2) {
int ans = 0;
int n1 = (Integer)o1;
int n2 = (Integer)o2;
if(n1>n2) ans = 1;
else if(n1<n2) ans = -1;
return ans;
}
// insert element to the tree
public void insertRecurs(Object elem) {
root = insertRecurs(root, elem);
}
BSTNode insertRecurs(BSTNode node, Object elem) {
if (node == null) {
return new BSTNode(elem);
}
if (compare(elem, node.data) < 0) {
node.left = insertRecurs(node.left, elem);
return node;
}
else{
node.right = insertRecurs(node.right, elem);
return node;
}
}
// search for element elem
public boolean find(Object elem) {
return find(root,elem);
}
boolean find(BSTNode tree, Object elem) {
if (tree == null)
return false;
if (compare(elem, tree.data) == 0)
return true;
if (compare(elem, tree.data) < 0)
return find(tree.left, elem);
else
return find(tree.right, elem);
}
// print all tree nodes
public void print() {
print(" ",root);
System.out.println();
}
void print(String s,BSTNode tree) {//Inorder
if (tree != null) {
print(s+"L ,",tree.left);
System.out.println(tree.data+" : "+s);
print(s+"R ,",tree.right);
}
}
///////////////////////////
public void remove(Object elem) {
root = remove(root, elem);
}
public static BSTNode remove(BSTNode node, Object n){
if(node != null){
if(compare(n,node.data) > 0){
node.right = remove(node.right,n);
}
else if(compare(n,node.data) < 0){
node.left = remove(node.left,n);
}
else{//the node that should be deleted is found
if(node.left == null && node.right == null){
node = null;
}
else if(node.left != null && node.right == null){//the node has only one child (left)
node = node.left;
}
else if(node.right != null && node.left == null){//the node has only one child (right)
node = node.right;
}
else{//node "tree" has two children
if(node.right.left == null){// his right node has only one child (right)
node.right.left = node.left;
node = node.right;
}
else{// remove the smallest element
BSTNode q, p = node.right;
while(p.left.left != null)
p = p.left;
q = p.left;
p.left = q.right;
node.data = q.data;
}
}
}
}
return node;
}
public void insertLoop(Object elem) {
BSTNode newNode = new BSTNode(elem);
if (root == null){
root = newNode;
}
else{
BSTNode n = root;
boolean flag = true;
while (flag){
if (compare(elem,n.data) > 0){
if (n.right != null) n = n.right;
else{
n.right = newNode;
flag = false;;
}
}
else{
if (n.left != null) n = n.left;
else{
n.left = newNode;
flag = false;;
}
}
}
}
}
public boolean isEmpty(){
return this.root == null;
}
//end of the code
the question is
how i build a function that give the max object in the BNT like this
public Object maximum(){
}
any Suggestions?
thank for yours help.
The maximum object in a Binary Search tree is the rightmost node. You can get it as follows :
1) Start from root node
2) Check if node.right is empty
3) If yes then node is the maximum object. terminate the search.
4) if not then move to rightmost nde (node = node.right) and repeat step 2.
Sample Code :
public BSTNode findMaxNode()
{
Node temp = root;
Node max = null;
while(temp != null)
{
max = temp;
temp = temp.right
}
return max;
}
I am having some problems printing an inOrder traversal of my binary tree. Even after inserting many items into the tree it's only printing 3 items.
public class BinaryTree {
private TreeNode root;
private int size;
public BinaryTree(){
this.size = 0;
}
public boolean insert(TreeNode node){
if( root == null)
root = node;
else{
TreeNode parent = null;
TreeNode current = root;
while( current != null){
if( node.getData().getValue().compareTo(current.getData().getValue()) <0){
parent = current;
current = current.getLeft();
}
else if( node.getData().getValue().compareTo(current.getData().getValue()) >0){
parent = current;
current = current.getRight();
}
else
return false;
if(node.getData().getValue().compareTo(parent.getData().getValue()) < 0)
parent.setLeft(node);
else
parent.setRight(node);
}
}
size++;
return true;
}
/**
*
*/
public void inOrder(){
inOrder(root);
}
private void inOrder(TreeNode root){
if( root.getLeft() !=null)
this.inOrder(root.getLeft());
System.out.println(root.getData().getValue());
if( root.getRight() != null)
this.inOrder(root.getRight());
}
}
It seems that you are not traversing the tree properly upon insertion, to find the right place for the new node. Right now you are always inserting at one child of the root, because the insertion code is inside the while loop - it should be after it:
public boolean insert(TreeNode node){
if( root == null)
root = node;
else{
TreeNode parent = null;
TreeNode current = root;
while( current != null){
if( node.getData().getValue().compareTo(current.getData().getValue()) <0){
parent = current;
current = current.getLeft();
}
else if( node.getData().getValue().compareTo(current.getData().getValue()) >0){
parent = current;
current = current.getRight();
}
else
return false;
}
if(node.getData().getValue().compareTo(parent.getData().getValue()) < 0)
parent.setLeft(node);
else
parent.setRight(node);
}
size++;
return true;
}
You insert method has a problem. It finds the right parent node to attach the new element to, but on the way it messes up the whole tree. You should move the insertion code out of the while loop:
public boolean insert(TreeNode node){
if( root == null)
root = node;
else{
TreeNode parent = null;
TreeNode current = root;
while( current != null){
if( node.getData().getValue().compareTo(current.getData().getValue()) <0){
parent = current;
current = current.getLeft();
}
else if( node.getData().getValue().compareTo(current.getData().getValue()) >0){
parent = current;
current = current.getRight();
}
else
return false;
}
if(node.getData().getValue().compareTo(parent.getData().getValue()) < 0)
parent.setLeft(node);
else
parent.setRight(node);
}
size++;
return true;
}
}
hey fellows here is one simple one.. try this out.. it works for me well...
public void levelOrderTraversal(Node root){
Queue<Node> queue = new ArrayDeque<Node>();
if(root == null) {
return;
}
Node tempNode = root;
while(tempNode != null) {
System.out.print(tempNode.data + " ");
if(tempNode.left != null) queue.add(tempNode.left);
if(tempNode.right != null) queue.add(tempNode.right);
tempNode = queue.poll();
}
}