New to Java. I learned BST tree insertion before with C++. But I try to replicate its recursive logic with Java like below:
public void tree_insert(Node x, int k) {
if (x == null)
x = new Node(k);
else if (k < x.val)
tree_insert(x.left, k);
else
tree_insert(x.right, k);
}
Suppose I have an empty tree
tree_insert(tree.root, 1);
But the root has not been changed.... I am guessing it may have to to with pass by reference in Java. But I am not exactly sure why it does not work. Some hint? Thanks.
What you are trying to do is assign a Node that has been passed by reference a new value. You already noted this and that is correct (I see that others stated this too).
How you would do this in java is by splitting up the recursion into two steps. EDIT: Not necessarily in java, but helper functions can be a good design to have in mind.
Introduce the insert function which null checks the root.
Private helper method that can generalise the insertion in the tree with recursive calls.
Here is an example:
public boolean insertBST(int value) {
if (root == null) {
root = new Node(value);
return true;
}
return insertBSTHelper(value, root);
}
private boolean insertBSTHelper(int value, Node node) {
if (node.value == value){
return false;
}
if (node.value > value){
if (node.left != null) {
return insertBSTHelper(value, node.left);
} else {
node.left = new Node(value);
return true;
}
} else {
if (node.right != null) {
return insertBSTHelper(value, node.right);
} else {
node.right = new Node(value);
return true;
}
}
}
Since there can only exist distinct elements in a BST, we check for these to ensure that we don't insert the same element twice.
Hope this helps!
Related
I want to delete a specific node using a key from a Ternary Search Tree. This works pretty well in most cases, but in some of my test sets, nodes that do not have a middle child also do not store values, which shouldn't happen.
I tried different methods I found online, but pretty much all of those few leave the tree in a dirty state, which makes searching a hassle, since you need to check if the leaf you found actually has a value, which shouldn't happen.
Here is my relevant code
private boolean hasChildren(Node x) {
return (x.left != null || x.mid != null || x.right != null);
}
private void reHang(Node x) {
if (hasChildren(x)) {
if (x.left != null) {
x.parent.mid = x.left;
x.left.right = x.right;
} else if (x.right != null) {
x.parent.mid = x.right;
}
}
}
private boolean remove(Node x, String key, int d) {
if (x == null) return false;
char c = key.charAt(d);
if (c < x.c) {
if (!remove(x.left, key, d)) {
x.left = null;
}
} else if (c > x.c) {
if (!remove(x.right, key, d)) {
x.right = null;
}
} else if (d < key.length() - 1) {
if (!remove(x.mid, key, d + 1)) {
x.mid = null;
if (x.val != null) return true;
}
} else {
x.val = null;
}
reHang(x);
return hasChildren(x);
}
private class Node
{
private Value val;
private char c;
private Node left, mid, right, parent;
}
Specifically, problems occur in this function I use for prefix lookups:
private Node getMidPath(Node x) {
if (x.left != null) return getMidPath(x.left);
if (x.mid == null) return x;
return getMidPath(x.mid);
}
Every Node that does not have a x.mid should have an x.val set, which is not always the case after remove, meaning I have dirty nodes.
Any help would be greatly appreciated.
You must see a ternary tree at was it is: Some nested Binary tree but witch each level have only on character as key instead of the whole string. Go down you binary trees until you string is exhausted. Here you will have two eventually references one to the actual data and and one two the actual subtree for longer string with same prefix. Now set the data to null. When the subtree reference is null remove the node. When now the entire subtree is empty continue with the subtree one character earlier. Here set subtree reference to null. Now is both references are null remove the node. When now the entire subtree is empty continue with the subtree one character earlier. And so on
I'm writing a program for class in Java regarding red/black trees. I've got a good understanding of how they usually work, and am supposed to use a recursive insertion method. What I would typically use is below, to match my professor's Node class. In regards to color, a 0 is black, a 1 is red. The Node class given to us does not deal with keys at all.
private static void put(int val, int col)
{ root = put(root, val, col); }
private static Node put(Node n, Integer val, int col)
{
if (n == null){
Node t=new Node(val);
t.setColor(1);
return t;
}
int cmp = val.compareTo(n.getValue());
if (cmp < 0) n.setLeft(put(n.getLeft(), val, col));
else if (cmp > 0) n.setRight(put(n.getRight(), val, col));
else n.setColor(col);
if (isRed(n.getRight()) && !isRed(n.getLeft())) n = rotateLeft(n);
if (isRed(n.getLeft()) && isRed(n.getLeft().getLeft())) n = rotateRight(n);
if (isRed(n.getLeft()) && isRed(n.getRight())) flipColors(n);
return n;
}
However, the catch is that we are supposed to return a boolean value--if the user inserts a duplicate value as is already on the tree, we return false and don't attach the node. Otherwise, we attach them and return true; the code given to us for this is below, but is not recursive (part of the project requirements). And while I hadn't implemented a way of balancing or rotating properly, the returned boolean part works.
public boolean insertNode(Node node) {
//Here is just an example of setting colors for a node. So far, it is in green color. But you need to modify the code to dynamically adjust the color to
//either RED or BLACK according to the red-black logic
Node current_node;
// if the root exists
if (root == null) {
root = node; // let the root point to the current node
root.setColor(Node.BLACK);
return true;
} else {
current_node = root;
node.setColor(1);
while (current_node != null) {
int value = current_node.getValue();
if (node.getValue() < value){ // go to the left sub-tree
if (current_node.getLeft() != null) // if the left node is not empty
current_node = current_node.getLeft();
else{ // put node as the left child of current_node
current_node.setLeft(node);
node.setParent(current_node);
current_node = null; }
//System.out.println("Left:"+current_node);
}
else if (node.getValue() > value){ // go to the right
if (current_node.getRight() != null) // if the right node is not empty
current_node = current_node.getRight();
else{ // put node as the right child of current_node
current_node.setRight(node);
node.setParent(current_node);
current_node = null; }
//System.out.println("Right: "+current_node);
}
else{
//System.out.println("Else: "+current_node);
return false; }
//if(current_node!=null&¤t_node.getLeft()!=null&¤t_node.getRight()!=null&¤t_node.getLeft().isRed()&¤t_node.getRight().isRed())
// flipColors(node);
}
}
if(node.getParent()!=null){
node=node.getParent();
System.out.println("Case: node has parent, val="+node.getValue());
}
if(node.getLeft()!=null&&node.getRight()!=null){
if((node.getRight().isRed())&&!node.getLeft().isRed())
node=rotateLeft(node);
if((node.getLeft().isRed())&&(node.getParent()!=null)&&(node.getParent().getLeft().getLeft()!=null)&&(node.getParent().getLeft().getLeft().isRed()))
node=rotateRight(node);
if((node.getLeft().isRed()) && (node.getRight().isRed()))
flipColors(node);
}
return true;
}
I wasn't able to find any comparable implementations online, and it seems that the boolean is necessary for the program's gui to work properly. If someone has a good suggestion for where to start, I would appreciate it!
For the recursive insertNode, I would suggest you the following: Create a function insertNode(Node node, Node current_node) which returns a boolean value. The idea is to always call the function insertNode for the currently investigated node, starting from the root node. If the node cannot be immediately added to current_node, the responsible node is called recursively to handle the node. I have provided you a short example based on your code (with some comments what the basic idea is, there is obviously some stuff missing). I hope, I got your question correctly and this helps you with your understanding.
public boolean insertNode(Node node) {
if (root == null) {
root = node;
root.setColor(Node.BLACK);
return true;
} else {
boolean result = insertNode(node, root);
if (result) {
//Some other important stuff to do...
}
return result;
}
}
public boolean insertNode(Node node, Node current_node) {
int value = current_node.getValue();
if (node.getValue() < value) {
if (current_node.getLeft() != null) {
// Investigate left
return insertNode(node, current_node.getLeft());
} else {
// Insert node left
return true;
}
} else if (node.getValue() > value) {
if (current_node.getRight() != null) {
// Investigate right
return insertNode(node, current_node.getRight());
} else {
// Insert node right
return true;
}
} else {
return false;
}
}
I now have the working functions, as below:
public boolean insertNode(Node node) {
if(root==null){
root=node;
root.setColor(Node.BLACK);
return true;
}
else
node.setColor(Node.RED);
return insertNode(node, root);
}
public boolean insertNode(Node node, Node cur){
if(node.getValue()<cur.getValue()){
if(cur.getLeft()!=null)
return insertNode(node, cur.getLeft());
else{
cur.setLeft(node);
node.setParent(cur);
handleInsertion(node);
return true; } }
else if(node.getValue()>cur.getValue()){
if(cur.getRight()!=null)
return insertNode(node, cur.getRight());
else{
cur.setRight(node);
node.setParent(cur);
handleInsertion(node);
return true; } }
else
return false;
}
The following is a simple implementation of Binary search tree using java. However, the code always outputs "BST empty!!" despite inserting elements. Where am I going wrong? I suspect I'm going wrong with recursion. Any help is greatly appreciated.
public class BinarySearchTree {
NODE root;
BinarySearchTree(){
root = null;
}
void insert(NODE nodeptr,int key){
if(root == null){
nodeptr = new NODE(key);
return;
}
if(nodeptr == null){
nodeptr = new NODE(key);
return;
}
if(key <= nodeptr.data){
insert(nodeptr.left,key);
}
else{
insert(nodeptr.right,key);
}
}
void inorder(NODE nodeptr){
if(nodeptr == null){
System.out.println("BST empty!!");
return;
}
inorder(nodeptr.left);
System.out.println(nodeptr.data + " ");
inorder(nodeptr.right);
}
/*driver program*/
public static void main(String args[]){
int[] a = {20,30,40,24,39};
BinarySearchTree bst = new BinarySearchTree();
for (int i: a){
bst.insert(bst.root,i);
}
bst.inorder(bst.root);
}
}
class NODE{
int data;
NODE left,right;
NODE(int data){
this.data = data;
left = null;
right = null;
}
}
Your insert method never assigns value to the root, so it remains null.
If I understand your code, your insert should look like this :
void insert(NODE nodeptr,int key){
if(root == null){
root = new NODE(key);
return;
}
if(nodeptr == null){
insert (root, key);
return;
}
if(key <= nodeptr.data){
if (nodeptr.left != null)
insert(nodeptr.left,key);
else
nodeptr.left = new NODE(key);
}
else{
if (nodeptr.right != null)
insert(nodeptr.right,key);
else
nodeptr.right = new NODE(key);
}
}
If the root is null, ignore the passed nodeptr and put key at the root of the tree.
If nodeptr is null, try to insert the new key starting at the root of the tree.
otherwise, once you find a null nodeptr.left or nodeptr.right, you must put the new key there, because if you make another recursive call, you would be passing a null Node to it, and the recursion would never end.
Expanding from Erans answer you could change it to:
public void insert(int key){
if(root == null){
root = new NODE(key);
return;
}
insert(root,key)
}
private void insert(NODE nodeptr,int key){
if(key <= nodeptr.data){
if(nodeptr.left == null){
nodeptr.left = new NODE(key)
}
else {
insert(nodeptr.left,key);
}
}
else{
if(nodeptr.right == null){
nodeptr.right = new NODE(key)
}
else {
insert(nodeptr.right,key);
}
}
}
Edit: As he has added his own code now its just a matter of what style you like better. A single method or two methods from which the public one has only one parameter.
I wanted my insert method something like this. Got it to working finally. Thank you all for your precious time.
NODE insert(NODE nodeptr,int key){
if(nodeptr == null){
nodeptr = new NODE(key);
}
else if(key <= nodeptr.data){
nodeptr.left = insert(nodeptr.left,key);
}
else{
nodeptr.right = insert(nodeptr.right,key);
}
return nodeptr;
}
I would call insert method from main something like this:
bst.root = bst.insert(bst.root,i);
The following is a class definition for my Linked List. I run a test program that creates a new LinkedList and inserts the numbers "3, 2, 1" and then prints the list. This works fine. However, when I try and delete "3" or "2," the delete method never completes. When I try and delete "1," it just prints out the complete list as if nothing had been deleted.
public class LinkedListTest implements LinkedList {
private Node head;
public LinkedListTest(){
head = new Node();
}
public void insert(Object x){
if (lookup(x).equals(false)){
if (head.data == null)
head.data = x;
else{
//InsertLast
Node temp = head;
while (temp.next != null){
temp = temp.next;
}
Node NewNode = new Node();
NewNode.data = x;
NewNode.next = null;
temp.next = NewNode;
}
}
//Runtime of insert method will be n, where n is the number of nodes
}
public void delete(Object x){
if (lookup(x).equals(true)){
if (head.data == x)
head = head.next;
else{
Node temp = head;
while (temp.next != null){
if ((temp.next).data == x)
temp.next = (temp.next).next;
else
temp = temp.next;
}
}
}
}
public Object lookup(Object x){
Node temp = head;
Boolean search = false;
if (head.data == x)
search = true;
while (temp.next != null){
if (temp.data == x){
search = true;
}
else{
temp = temp.next;
}
}
return search;
}
public boolean isEmpty(){
if (head.next == null && head.data == null)
return true;
else
return false;
}
public void printList(){
Node temp = head;
System.out.print(temp.data + " ");
while (temp.next != null){
temp = temp.next;
System.out.print(temp.data + " ");
}
}
}
EDIT: Here is the node class:
public class Node {
public Object data;
public Node next;
public Node(){
this.data = null;
this.next = null;
}
}
There are a few issues here.
The first big issue is that in your lookup() and your delete() methods, you don't break out of your loops when a successful condition occurs. This is why your program is hanging; it's in an infinite loop.
It's also worth noting a this point is that it's an incredibly bad practice not to use curly braces with all if/else statements. There's no reason not to do so, and it can introduce bugs easily when you don't.
in lookup() you should have:
if (head.data == x) {
search = true;
} else {
while (temp.next != null){
if (temp.data == x){
search = true;
break;
} else {
temp = temp.next;
}
}
}
and in delete():
if (head.data == x) {
head = head.next;
} else {
Node temp = head;
while (temp.next != null) {
if (temp.next.data.equals(x)) {
temp.next = temp.next.next;
break;
} else {
temp = temp.next;
}
}
}
Now this will produce what you expect:
public static void main( String[] args )
{
LinkedListTest llt = new LinkedListTest();
llt.insert(1);
llt.insert(2);
llt.insert(3);
llt.printList();
System.out.println();
llt.delete(2);
llt.printList();
}
Output:
1 2 3
1 3
However, that doesn't expose your second, larger issue. You're comparing reference values using == when looking at the node's data.
This "works" at the moment because of a side-effect of auto-boxing small integer values; you're getting the same object references. (String literals would also "work" because of the string pool). For more info on this, look at How do I compare Strings in Java and When comparing two integers in java does auto-unboxing occur
Let's look at this:
public static void main( String[] args )
{
LinkedListTest llt = new LinkedListTest();
llt.insert(1000);
llt.insert(2000);
llt.insert(2000);
llt.insert(3000);
llt.printList();
System.out.println();
llt.delete(2000);
llt.printList();
}
Output:
1000 2000 2000 3000
1000 2000 2000 3000
lookup() stopped working, allowing a duplicate to be inserted. delete() stopped working as well.
This is because int values over 127 auto-box to unique Integer objects rather than cached ones (see the linked SO question above for a full explanation).
Anywhere you're using == to compare the value held by data needs to be changed to use .equals() instead.
if (temp.data.equals(x)) {
With those technical issues solved, your program will work. There's other things that you should consider though. The two that jump right out are:
lookup should return a boolean.
There's no need to call lookup() in delete()
lookup itself is a fairly inefficient approach as a separate method; An insert iterates through the entire list twice.
First of all why does lookup return an object? change it to boolean.
also your "while" loop in lookup() doesn't advance. you need to remove the "else".
your delete function seems fine though.
I think you got quite some things wrong.
First of all, when you use LinkedList all of the functionality you tried to implement already exists.
Furthermore your style is relatively bad. For example, why do you use the WrapperClass Boolean for lookup?
Combining functionality like contains with something like get in one method is not a good idea. Split this up in two methods, let contains just return a boolean and test if an element exists in the list. Let get search and return for an element.
In addition to this you try to compare the Objects via equal. If you have not overwritten equals you can not delete anything ever, because equals needs reference equality which is not given most times.
I would highly recommend that you buy a java book or something to improve your overall knowledge..
So this is my first java program, but I've done c++ for a few years. I wrote what I think should work, but in fact it does not. So I had a stipulation of having to write a method for this call:
tree.insertNode(value);
where value is an int.
I wanted to write it recursively, for obvious reasons, so I had to do a work around:
public void insertNode(int key) {
Node temp = new Node(key);
if(root == null) root = temp;
else insertNode(temp);
}
public void insertNode(Node temp) {
if(root == null)
root = temp;
else if(temp.getKey() <= root.getKey())
insertNode(root.getLeft());
else insertNode(root.getRight());
}
Thanks for any advice.
// In java it is little trickier as objects are passed by copy.
// PF my answer below.
// public calling method
public void insertNode(int key) {
root = insertNode(root, new Node(key));
}
// private recursive call
private Node insertNode(Node currentParent, Node newNode) {
if (currentParent == null) {
return newNode;
} else if (newNode.key > currentParent.key) {
currentParent.right = insertNode(currentParent.right, newNode);
} else if (newNode.key < currentParent.key) {
currentParent.left = insertNode(currentParent.left, newNode);
}
return currentParent;
}
Sameer Sukumaran
The code looks a little confusing with overloaded functions. Assuming member variables 'left' and 'right' to be the left child and right child of the BSTree respectively, you can try implementing it in the following way:
public void insert(Node node, int value) {
if (value < node.value)
{
if (node.left != null)
{
insert(node.left, value);
}
else
{
node.left = new Node(value);
}
}
else if (value > node.value)
{
if (node.right != null)
{
insert(node.right, value);
}
else
{
node.right = new Node(value);
}
}
}
........
public static void main(String [] args)
{
BSTree bt = new BSTree();
Node root = new Node(100);
bt.insert(root, 50);
bt.insert(root, 150);
}
You should have a look to this article. It helps to implement a tree structure and search, insert methods:
http://quiz.geeksforgeeks.org/binary-search-tree-set-1-search-and-insertion/
// This method mainly calls insertRec()
void insert(int key) {
root = insertRec(root, key);
}
/* A recursive function to insert a new key in BST */
Node insertRec(Node root, int key) {
/* If the tree is empty, return a new node */
if (root == null) {
root = new Node(key);
return root;
}
/* Otherwise, recur down the tree */
if (key < root.key)
root.left = insertRec(root.left, key);
else if (key > root.key)
root.right = insertRec(root.right, key);
/* return the (unchanged) node pointer */
return root;
}
You can use standard Integer (wrapper for primitive int) object instead of creating a new object type Node. On latest java Integer/int auto-boxing is supported. Hence your method insertNode(int key) can take in Integer argument too (ensure it is not null).
EDIT: Pls ignore above comment. I did not understand your real question. You will have to overload insertNode(). I think you are right.
but where is temp when you insertNode?? With your current implementation temp is lost if root is not null.
I think you want something like
root.getLeft().insertNode(temp);
and
root.getRight().insertNode(temp);
i.e. To insert the new Node (temp) to either the left or the right subtree.