Java Binary tree insert is not working properly - java

When i add a node for example, named "Bob" in the insert method:
public void insert(String aLabel){
//left recursion:
if(this.getLabel().compareTo(aLabel) <= 0) {
if (childrenLeft == null) {
BSTreeNode aNode = new BSTreeNode(aLabel,this);
return;
}
else {
childrenLeft.insert(aLabel);
}
}
//right recursion
else {
if (childrenRight==null) {
BSTreeNode aNode = new BSTreeNode(aLabel,this);
return;
}
else{
childrenRight.insert(aLabel);
}
}
}
my tree only adds a blank node with no label on the left side of the treee only. is there something wrong with the (BSTreeNode aNode = new BSTreeNode;)? because when i hard code the nodes like:
BSTreeNode Louis = new BSTreeNode("Louis", treeRoot);
BSTreeNode bonny = new BSTreeNode( "bonny", treeRoot);
BSTreeNode Sue = new BSTreeNode("Anne", bonny);
BSTreeNode Sam = new BSTreeNode("Sam",Louis);
BSTreeNode Anne2 = new BSTreeNode( "delta", bonny);
BSTreeNode Frank = new BSTreeNode("Kalle", Louis);
the tree shows both a label and is inserted at the desired location.
other code-
the constructor:
public BSTreeNode( String aLabel,BSTreeNode aParent){
label = aLabel;
parent = aParent;
//add this node as a child of this node's parent either left or right
if(parent != null){
if(parent.getLabel().compareTo(label)<= 0) {
parent.addLeftChild(this);
}
if(parent.getLabel().compareTo(label)> 0) {
parent.addRightChild(this);
}
}
}
this is the constructor that adds the node to the parent when a node is created.
add childleft and right methods:
private void addLeftChild(BSTreeNode aNode){
if(childrenLeft == null) this.childrenLeft = aNode;
}
private void addRightChild(BSTreeNode aNode) {
if(childrenRight == null) this.childrenRight = aNode;
}

Most binary trees follow a different style, and set the parent's left/right child inside the recursive method, instead of the child going up and telling somebody it's their new parent
This code is a bit more standard for how most binary trees function:
public void insert(String aLabel)
{
if(getLabel().compareTo(aLabel) <= 0)
if(childrenLeft == null)
childrenLeft = new BSTreeNode(aLabel, this);
else
childrenLeft.insert(aLabel);
else
if(childrenRight == null)
childrenRight = new BSTreeNode(aLabel, this);
else
childrenRight.insert(aLabel);
}
That code should correctly save the values of the BSTreeNodes being created, and has the added effect of being less confusing as to how a parent is getting it's child
It makes a whole lot more sense to most people for a parent to be getting a child, instead of a child reaching up to a node and telling it that it's the new child on the block

You logic might be a little flawed.
When adding from your constructor, you're calling addLeftChild or addRightChild directly. These function check if the node on the right/left is null or not and adds the value if its null. But what if it's not null. It should then compare to the left/right child and continue because otherwise the nodes do not get added (i.e. the function falls through & doesn't return anything as its void).

Related

BST implementation java

I studied C++ , but I am quite new to Java.I am trying to write a binary search tree(BST) class.Here is my code:
public class binary_tree {
public class node
{
int data;
node left , right;
node(int data , node left , node right)
{
this.data = data;
this.left = left;
this.right = right;
}
}
private node root = null;
public void addElement(int x)
{
addElementNotSeen(x , this.root);
//this function allows the user to only give x
//as a parameter
}
private void addElementNotSeen(int x , node curent)
{
if (curent == null)
{
curent = new node(x , null , null);
}
else
{
if (x > curent.data)addElementNotSeen(x , curent.right);
else addElementNotSeen(x , curent.left);
}
}
}
However , my root seems to not get any value.I've seen that in Java you don't need to pass arguments by reference so I can't see the problem.Can you help me?
When you check if node is null and then create it, you are actually creating a new node for the reference of the parameter, not for the original reference that you passed outside the function.
So, instead of checking if node is null in addElementNotSeen, check if this.root is null in addElement, and instantiate directly.
public void addElement(int x)
{
if(this.root == null)
this.root = new node(x, null, null)
else
addElementNotSeen(x , this.root)
}
The same goes when passing recursively the data down your tree. Don't risk to pass null as a parameter. Check if left or right are null and if so, create them directly, as in the previous example with this.root.
private void addElementNotSeen(int x , node curent)
{
else
{
if (x > curent.data){
if (curent.right == null)
curent.right = new node(data, null, null);
else
addElementNotSeen(x , curent.right);
}else{
// the same for left
}
}
}
This line of code
curent = new node(x , null , null);
doesn't have any effect outside of addElementNotSeen since it modifies local reference only.
See Oracle docs:
Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object's fields can be changed in the method, if they have the proper access level.

Recursion of Linked List

When given an array of integers, I'm trying to change each element with the product of the integers before it.
For example, int[] array = {2,2,3,4}; is now: {2, 4, 12, 48};
I added each element to a LinkedList, and I'm trying to do this recursively.
This is what I have:
Node curr = list.getFirst();
product(curr);
public static void product(Node curr)
{
if(curr == null)
{
return;
}
else
{
int data = curr.getData() * curr.getNext().getData();
Node newNode = new Node(data);
curr.setNext(newNode);
// product(curr);
}
}
The first product works: {2,4}, but when I try to put in the recursion, I get a stackoverflow. Any suggestions??
Edit: So the reason that I'm either getting a stackoverflow or null pointer exception is because I'm updating the list, and then trying to get the next integer(but since there's only two elements in the list, there isn't a getNext()). I'm not sure how to fix this.
It looks like you were getting a bit tied up in the recursion. I modified your method to accept a Node along with the product from the previous iteration. At each step of the iteration I update the value in the already-existing List, so there is no need for using the new operator.
public static void product(Node curr, int value) {
if (curr == null) {
return;
}
else {
int data = value * curr.getData(); // compute current product
curr.setData(data); // update Node
product(curr.getNext(), data); // make recursive call
}
}
There are actually two issues with the code.
The recursion never ends, i.e. it is not actually moving to a smaller "subproblem" as the recursion is calling the same node again
and again.
After creating a new node and modifying the next we also need to connect the node "after" the next node otherwise the link will be
lost. Please check the below method which addresses both the issues.
Although I didn't do an excessive testing it is working for simple dataset.
Original List:
2->4->5->6->8->null
Multiplied List:
2->8->40->240->1920->null
public void product(Node curr) {
if (curr.getNext() == null) {
return;
} else {
int data = curr.getData() * curr.getNext().getData();
Node newNode = new Node();
newNode.setData(data);
Node nodeAfterNextNode = curr.getNext().getNext();
newNode.setNext(nodeAfterNextNode);
curr.setNext(newNode);
product(newNode);
}
}
It is because you call recursive method on the current node, so it is actually never move forward in the LinkedList. You can simply update the next node's data and call the recursive method on it. See the code below:
Node curr = list.getFirst();
product(curr);
public static void product(Node curr)
{
Node next = curr.getNext();
if(next == null)
{
return;
}
else
{
int data = curr.getData() * next.getData();
next.setData(data);
product(next);
}
}

Deleteing a Node in a Binary tree

Iunderstand the basis of a deletion algorithm in a Binary Search tree and have created the following code to delete the largest value from the tree.
public void DelLargest()
{
Node<T> del = this;
boolean child = this.left.empty();
boolean child2 = this.right.empty();
right.DelLargest();
if(child && child2)
this.head = null;
else if(child == true && child2 == false)
this.head = left;
}
Basically what I have is that the recursion runs until 'this' is the rightmost node and then checks two cases, whether 'this' is a leaf, or whether 'this' has a left child. (The other case normally associated with this kind of algorithm is redundant because in finding the node with the largest value, I have gone as right as I can go.) The trouble I am having is getting the current node to then either point to null or to the value at Node left.
Note : This is what my instructor referred to as a "modern" Binary search Tree wherein a vertex or "filled" node and a nil or "empty" node are two subclasses of Interface Node which define the characteristics of each type.
I've managed to narrow the problem down to the fact that I do not have a method that returns a value of a given Node. Working on that now, input would be appreciated.
As suggested in the other answer you should use iterative approach.
In a BST the largest value is the rightmost node.
So do a scan and keep going right until you hit a null.
In the scan keep track of three nodes. (gpnode, pnode, node).
Once the scan is done you will have (gpnode,pnode,null)
Now there are 2 cases.
case 1:
pnode is a leaf. So change the edge (gpnode,pnode) to (gpnode,null)
case 2: (EDITED)
pnode.lChild is not null. Note that pnode.rChild will be null as the search would have terminated at that point.
Now change the edge (gpnode,pnode) to (gpnode,pnode.lChild)
Here is the pseudo code:
public class Node
{
long key;
Node lChild;
Node rChild;
}
public void DelLargest()
{
Node gpnode = null;
Node pnode = null;
Node node = root;
while(node != null) // keep going right until a null is reached
{
gpnode = pnode;
pnode = node;
node = node.rChild;
}
if(pnode.lChild == null) // its a leaf node So change the edge (gpnode,pnode) to (gpnode,null)
{
if(gpnode.lChild == pnode)
{
gpnode.lChild = null;
}
else
{
gpnode.rChild = null;
}
}
else // copy lChild's key to this node and delete lChild
{
if(gpnode.lChild == pnode)
{
gpnode.lChild = pnode.lChild;
}
else
{
gpnode.rChild = pnode.lChild;
}
}
}
You've got the right idea. What you want to do is keep a reference to the right most nodes parent, and the right most nodes left child so then when you delete it you can attach the two.
Here's an iterative solution. This will generally be more efficient than recursion, but if you want recursion you should be able to adapt it:
public void delLargest() {
// get rightmost node's parent
Node<T> current = root;
while(current.right != null && current.right.right != null) {
current = current.right;
}
// get the rightmost nodes left node
Node<T> left = current.right.left;
// attach the parent and left
current.right = left;
// nothing points to the right most node anymore, so it will be garbage collected
}

With Binary Trees, I want to add the next node in consecutive order, my algorithm isn't quite working however

For instance, if I had
A
/ \
B C
/
D
I would want the next addition to be:
A
/ \
B C
/ \
D E
But I'm having a lot of trouble detecting where the next spot for the item to input will be. I have the following code:
public static BinaryTree<String> addToTree(BinaryTree<String> tree, String name) {
if (tree.getLeft() == null) {
BinaryTree<String> newTree = new BinaryTree<String>();
newTree.makeRoot(name);
tree.attachLeft(newTree);
}
else if (tree.getRight() == null) {
BinaryTree<String> newTree = new BinaryTree<String>();
newTree.makeRoot(name);
tree.attachRight(newTree);
}
// Both are non-null
else {
if (tree.getLeft().getLeft() == null || tree.getLeft().getRight() == null) {
tree.attachLeft(addToTree(tree.getLeft(), name));
}
else if (tree.getRight().getLeft() == null || tree.getRight().getRight() == null) {
tree.attachRight(addToTree(tree.getRight(), name));
}
}
return tree;
}
But it will only work for up to a three level tree. If I try to add the fourth, it no longer adds any.
How do I implement it so it will figure out where the next item is null, and then add it there?
I also thought of having a checkNullity() method, wherein I'd take a tree, and check if its children were null, but I was also having trouble figuring out how to get the children's children. I wanted to find where it was null and then add it there.
Could anyone offer some input?
You can modify breadth first traversal to accomplish this I think. When you pop up the items from the queue, check if any of the children is empty. The first empty child slot is the place you want to add to.
addNode(root, newNode)
q = empty queue
q.enqueue(root)
while not q.empty do
node := q.dequeue()
if node.left == null
//create new node as nodes left child
return
q.enqueue(node.left)
if node.right == null
//create new node as nodes right child
return
q.enqueue(node.right)
Since, you want to insert the element in the order from left to right and starting from the same level. I would suggest you to look in to Breath First Search. I have provided an basic implementation.
public void insert(child, root){
if (root == null){
root = child
}
Node iter = root
Myqueue q = new Myqueue(); //Implementation of the Java Queue Interface
while (iter!=null){
//Check: If the left node exists, enque in the que
if(iter.is_left()){
q.insert(iter.left)
}
else{
iter.left = child
iter = null
}
//Similary for the right
if(iter.is_right()){
q.insert(iter.right)
}
else{
iter.right = child
iter = null
}
if (iter != null){
iter = q.poll() //Retreiving the head of the queue
}
}
}
You could enumerate all nodes while adding them to the tree. If you want to add the n-th node to the tree, it'll be a child of the n/2-th node: left if n%2 == 0 and right if n%2 == 1.
This certainly creates the tree you are asking for although I am still not sure it is what you want:
public class BinaryTree<T> {
T root = null;
BinaryTree<T> left = null;
BinaryTree<T> right = null;
public BinaryTree<T> getLeft() {
return left;
}
public BinaryTree<T> getRight() {
return right;
}
public void makeRoot(T root) {
this.root = root;
}
public void attachLeft(BinaryTree<T> tree) {
left = tree;
}
public void attachRight(BinaryTree<T> tree) {
right = tree;
}
public static BinaryTree<String> addToTree(BinaryTree<String> tree, String name) {
if (tree.getLeft() == null) {
BinaryTree<String> newTree = new BinaryTree<String>();
newTree.makeRoot(name);
tree.attachLeft(newTree);
} else if (tree.getRight() == null) {
BinaryTree<String> newTree = new BinaryTree<String>();
newTree.makeRoot(name);
tree.attachRight(newTree);
} else {
addToTree(tree.getLeft(), name);
}
return tree;
}
public static void main(String[] args) {
try {
BinaryTree<String> tree = new BinaryTree<String>();
String add = "ABCDEFG";
tree.makeRoot(add.substring(0, 1));
for (int i = 1; i < add.length(); i++) {
addToTree(tree, add.substring(i, i + 1));
}
System.out.println("Done");
} catch (Throwable e) {
e.printStackTrace();
}
}
}
Added
I have clearly misunderstood the question. Perhaps an example will help.
If I added one character at a time (as strings) from the following string what would you expect?
"ABCDEFG"
A
/ \
B C
/ \ | \
D E F G?
or something else.
What would you then expect from
"ADEFGBC"
A
/ \
D E
/ \ | \
F G B C
or
A
/ \
B C
/ \ | \
D E F G
or something else?
Either is possible but I cannot see any value in either case.
In order to add an element to a proper place in a binary tree, you have to go from the root at at each node answer the following question: Should I descend to the left or to the right subtree? This is what your problem boils down to - how to make this decision at each node.
You start is OK. If the node has no left subtree, then the newly added leaf should be its left child. And if the node has a left subtree but no right subtree, then the newly added leaf should be its right child.
But how to decide if the node has both subtrees? For this you'll need to keep some sort of information at the nodes that you can use to decide. One possibility is to keep at each node the total size of its subtree. Then if both subtrees have the same size, it means both are perfectly balanced and so you add to the left. Otherwise, if the left subtree has size 2^n-1 it means that it's balanced (and the right one is not) so you add to the right. If not, add to the left.
However, you can do much simpler than that. Since your trees always keep this structure, you can represent a tree as an ArrayList. The root node is at index 0 and for a node at index n its children are at indexes _2*n+1_ and _2*n+2_. This is just how binary heaps are implemented. This way, you'll get O(1) time complexity for adding a new node - simply append it at the end of the list. (However, if you need some classical tree operations like rotations, this implementation won't work.)

inserting nodes into a binary tree in java question

im coming from c++ to java and i am confused on binary trees with java. is the only way to have a Node class is to make it an inner static class? all the examples i see do this. However, the way im doing it is i have a node class and a binarytree class uses this node class. but i keep getting an error when i try inserting into the tree after the second insert. i get an exception at this line if(dataIn <= nodeIn.getLeft().getData()){
I am confused as to what i did wrong.... here is my code for insert that i have. thanks in advance..
public void insert(int dataIn){
root = insert(root, dataIn);
}
private Node insert(Node nodeIn, int dataIn){
if(nodeIn==null){
nodeIn = new Node(null, null, dataIn);
}else{
if(dataIn <= nodeIn.getLeft().getData()){
nodeIn.setLeft(insert(nodeIn.getLeft(), dataIn));
}else{
nodeIn.setRight(insert(nodeIn.getRight(), dataIn));
}
}
return nodeIn;
}
Part of the reason it's confusing is that "Node" should not be a parameter to the insert method, you should be calling an insert method defined in node.
So let's say you hold the "Root" node in your "normal code"--let's call it "rootNode" just to be obscure.
Okay, so your code to insert into the tree would be:
rootNode.insert(newValue);
Easy enough.
Now to define that method.
public class Node {
private int value;
private Node lower;
private Node higher;
public void insert(int newValue) {
if (newValue < value)
if(lower == null)
lower=new Node(value);
else
lower.insert(newValue);
else
if(higher == null)
higher=new Node(value);
else
higher.insert(newValue);
}
// and you'll need a constructor
public Node(int value) {
this.value=value;
}
}
This should read much more clearly. I'm going to hit "Post" then I'm going to edit it and figure out how to easily refractor that evil evil copy & paste code.
On second thought, I'll leave it there because it's more readable. The best fix I can see is to make the nodes an array, then you get:
public class Node {
private int value;
private Node[] nodes=new Node[2];
private final int LOWER=0;
private final int HIGHER=1;
public void insert(int newValue) {
int index=LOWER;
if (newValue > value)
index=HIGHER;
if(nodes[index] == null)
nodes[index]=new Node(value);
else
nodes[index].insert(newValue);
}
}
But I won't replace the original because, as I said, it's clearer.
I recommend the refactoring book for more of this. It really does help simplify your code once you really get OO. Passing an object to an otherwise static method (one that doesn't use member variables) is a dead give-away.
With more considerations about #ted's comment and OO--getLeft and getRight shouldn't even be an issue. Neither is necessary outside the abstraction.
In general what you probably need is these methods in Node:
public boolean doesContain(int value) {
if(value == this.value)
return true
else
return nodes[ this.value < value ? LOWER : HIGHER].doesContain(value);
}
and maybe
public void getValuesSorted(LinkedList l) {
nodes[LOWER].getValuesSorted(l);
l.put(value);
nodes[HIGHER].getValuesSorted(l);
}
Then you don't even need to expose that it's a tree you are dealing with--beter OO abstraction.
You need to test whether nodeIn.getLeft() == null.
is the only way to have a Node class is to make it an inner static class? all the examples i see do this.
No.
The Node class doesn't need to be an inner or nested class. (Strictly speaking a "static inner" class is a nested class.)
However, only an inner or nested class can be private. If your Node class is a regular class you are exposing implementation details to (at least) other classes in the same package. This is a bad idea ... and that explains why you see the Node class declared the way it is.
you can use the below code to clear your understanding. Mostly we do not use any other class everything can be done inside a single Node class itself. here is a very basic example which i believe might be helpful... Also when i see you have two methods in which you have only provided data rather than root. Trust me it is better to have root in your main class. reasoning we have it handy where ever we need to cache.
public Node insert(Node root, Node newNode) {
if (root == null) {
root = newNode;
} else {
if(root.data > newNode.data) {
root.left = insert(root.left, newNode);
} else {
root.right = insert(root.right, newNode);
}
}
return root;
}
directly call this method from any class where you have initialized. here is a sample plz check..
Node root = new Node(10);
root.insert(root, new Node(5));
root.insert(root, new Node(3));
root.insert(root, new Node(6));
root.insert(root, new Node(1));
Instead of:
if (dataIn <= nodeIn.getLeft().getData()) {
... you want:
if (dataIn < nodeIn.getData()) {
You need to compare the value that is to be inserted with the value at the current node.
I changed the <= sign to a < sign so that duplicates are avoided.
So your code refactored is:
public void insert(int dataIn) {
root = insert(root, dataIn);
}
private Node insert(Node nodeIn, int dataIn){
if (nodeIn == null) {
nodeIn = new Node(null, null, dataIn);
} else {
if (dataIn < nodeIn.getData()) {
nodeIn.setLeft(insert(nodeIn.getLeft(), dataIn));
} else {
nodeIn.setRight(insert(nodeIn.getRight(), dataIn));
}
}
return nodeIn;
}
Actually, for a binary tree there is no need to check whether the inserting element is either greater than or left than the parent node. I think there is no need of checking those conditions. We have to take the input from user whether to insert right or left.
public class TreeNode
{
private int data;
private TreeNode left;
private TreeNode right;
public Tree( )
{
data = 0;
left = null;
right = null;
}
public Tree( int initialInfo, TreeNode initialLeft, TreeNode initialRight )
{
data = initialInfo;
left = initialLeft;
right = initialRight;
}
public void setLeft( TreeNode newLeft )
{
left = newLeft;
}
public void setRight( TreeNode newRight )
{
right = newRight;
}
public void insert( int element )
{
if( element <= data )
{
if( left == null )
setLeft( new TreeNode( element, null, null ) );
else
left.insert( element );
}
else
{
if( right == null )
setRight( new TreeNode( element, null, null ) );
else
right.insert( element );
}
}
}
All your solutions do not take into accoount what would happen if the node was to be inserted in the middle of the tree. You are assuming that it will also be smallest or greatest. When you insert something in the middle of the tree, then you will realize that the operation becomes more complex.

Categories