Java: Binary Search Tree - java

I decided to create a Binary Search Tree using java, and what I want to do is delete the Max element from the tree, so I created this part of code:
public Node<T> removeMax(Node<T> node) {
if (node == null)
return null;
if (node.right == null) {
Node<T> n = node;
node = null;
return n;
}
return removeMax(node.right);
}
The method returns the Max element, but it doesn't remove it from the tree. As you can see, I tried to remove it in this part:
Node<T> n = node;
node = null;
return n;
But, when I print the elements in the tree, it shows the "removed" ones too.
What am I doing wrong?
EDIT: What I'm really trying to do is delete the Max node and return it so I can now which one was deleted.

Now I noticed you wanted to know which node gets deleted. All you can do is to delete the maximum node and print the tree:
public void deleteMax(Node<T> root) {
Node<T> current = root;
while (current.right.right != null) {
current = current.right;
}
if(current.right.left!=null) {//max has 1 child to left
current.right=current.right.left;
}
else {//max has no child
current.right=null;
}
}
public String printInfix(Node<T> root) {//prints all the data in the tree in infix order
if(root==null) {
return "";
}
return printAll(root.left+" "+root.data+" "+printAll(root.right);
}

You want to delete a node in a binary search tree. So, basically what you want to do is to make it inaccessible. To do that, you have to nullify the reference to it, i.e, make its parent's corresponding pointer to it as null.
Change this:
if (node.right == null) {
Node<T> n = node;
node = null;
return n;
}
To this:
if (node.right.right == null) {
Node<T> n = node.right;
node.right = node.right.left;
return n;
}
Also you need to take care of the case when the root is the maximum element of the tree. So, if you have some reference to the root of BST, add this case before the above case:
if (node.right == null) {
Node<T> n = node;
referenceToTheRootOfBST = node.left;
return n;
}
If you don't have a reference to the root of the BST, what you can do is deep copy the left node of the root and then remove the left node. So, the above case changes to:
if (node.right == null) {
Node<T> n = node;
//I'll assume you don't call this function if root is the only element.
//if root is the only element.If that's the case, then just make the
//root null before calling this function.
Node<T> leftNode = node.left;
node.value = leftNode.value;
node.left = leftNode.left;
node.right = leftNode.right;
return n;
}
Another simple way to handle the case that root is the maximum element is to check it before actually calling this function. Simply check if root has a right node, and if it doesn't have it, reallocate the root reference.

Related

Generic binary search tree isn't adding new nodes correctly (Java)

I'm writing a binary search tree in java with generic classes, but the nodes aren't adding correctly and I can't figure out why.
Here's my insert method (iterative):
public void insert (E element){
//iterative insert element to tree
Node<E> node = new Node<>(element); //create new node for element
Node<E> current = root;
if (root == null) root = node; // if no root, new node is the root
else {
while (current != null){ //traverse tree to get to correct parent node
if (element.compareTo(current.data) < 0) { //case 1: node is smaller than current
if (current.left == null){
node.parent = current;
current.left = node;
}
else {
current = current.left;
}
}
else if (element.compareTo(current.data) > 0) { //case 2: node is larger than current
if (current.right == null){
node.parent = current;
current.right = node;
}
else {
current = current.right;
}
}
else { //case 3: node already exists
throw new RuntimeException("Node already exists");
}
}
}
size++;
}
the problem happens when I'm running my test class. there first node is added and becomes the root, but the next insert after that throws the exception no matter what the value is. It's acting like the value I'm trying to add already exists in the tree. If I comment out the exception, the test class doesn't compile, as if it's running an infinite loop.
What am I doing wrong here?
How would current ever become null in your while loop?
You don't break out from your while loop even when you insert new element:
if (current.left == null) {
node.parent = current;
current.left = node;
}
On the next iteration you assign current to the value you just inserted into current.left:
} else {
current = current.left;
}
and yet on the next iteration you now have current.data equal to element, which leads to the exception. Add break; after you insert the element:
if (current.left == null) {
node.parent = current;
current.left = node;
break;
}

Removing a node from Binary Search Tree (BTS), and successor method

In my new class assignment, one of the classes in my program I have to write is a BinarySearchTree class. There are 2 methods on which I am struggling a bit, and that's the remove method and successor method.
The binary search tree only stores data in the internal nodes, so the leaf nodes are empty, but not null. however in my remove method I always get an nullPointerException at if(parent.getLeft() == nodeToBeRemoved) and I am not sure why.
Here is my code for remove method:
public void remove(Pair k) throws DictionaryException {
BinaryNode nodeToBeRemoved = searchTreeNode(root, k); //Searches the tree for the node to be removed.
if(nodeToBeRemoved.isLeaf()) { //If the search returns a leaf node, the node to be removed is not in the tree.
throw new DictionaryException("key");
} else {
//If the node to be removed has one child (plus one leaf child) or both children are leaf nodes.
if(nodeToBeRemoved.getLeft().isLeaf() || nodeToBeRemoved.getRight().isLeaf()) {
BinaryNode childNode;
if(nodeToBeRemoved.getLeft().isLeaf()) {
childNode = nodeToBeRemoved.getRight();
} else {
childNode = nodeToBeRemoved.getLeft();
}
BinaryNode parent = nodeToBeRemoved.getParent(); //Parent of the node to be removed.
if(nodeToBeRemoved == root) { //If the node to be removed is the root, the child is set to be the new root.
root = childNode;
} else {
if(parent.getLeft() == nodeToBeRemoved) {
parent.setLeft(childNode);
} else {
parent.setRight(childNode);
}
}
} else { //If the node to be removed has two children (non leaf children).
BinaryNode successorNode = smallestNode(nodeToBeRemoved.getRight()); //Finds the successor node of the node to be removed.
nodeToBeRemoved.setData(successorNode.getData()); //Sets the node to be removed data to be the successor node's data.
remove(successorNode.getData().getKey()); //The successor is then removed.
}
}
}
and my put method, in case it's actually something wrong with that:
public void put(Record r) throws DictionaryException {
BinaryNode newNode = searchTreeNode(root, r.getKey()); //Searches the tree for the node.
if(!newNode.isLeaf()) { //If the node is not a leaf, then the data is already in the tree, so exception is thrown.
throw new DictionaryException("key");
} else { //Otherwise, the data item is not in the tree, and will be added.
newNode.setData(r);
newNode.setLeft(new BinaryNode()); //Sets the left child to be a leaf node.
newNode.setRight(new BinaryNode()); //Sets the right child to be a leaf node.
}
}
The successor method takes in key "k" and returns the data stored in the successor node, however the key "k" does not have to be stored in any of the node in the tree already, so what I did was temporarily added it to the tree, found the successor node and then removed it using the remove method. However, using the test.java file I received from the prof, this method fails the test. Here is my successor code:
public Record successor(Pair k) {
boolean added = false; //A boolean variable to determine if the key is added to the tree.
BinaryNode tempNode = root;
//If the key is not in any of the nodes in the tree, then add this node to the tree.
if(searchTreeNode(tempNode, k).isLeaf()) {
put(new Record(k, null));
added = true; //sets added to true, showing that the node with "key" was added.
}
BinaryNode inputNode = searchTreeNode(tempNode, k);
//If the right child of the node is not null, then the successor is the smallest node in the right subtree.
if(!inputNode.getRight().isLeaf()) {
return smallestNode(inputNode.getRight()).getData();
}
//Otherwise, we have to search up the tree until the parent of the node is the left child of another node. then
//That "another node" will be the first right ancestor, which is the successor node.
BinaryNode inputNodeParent = inputNode.getParent();
while(inputNodeParent != null && inputNode == inputNodeParent.getRight()) {
inputNode = inputNodeParent;
inputNodeParent = inputNodeParent.getParent();
}
Record dataValue = inputNodeParent.getData();
//If the key is added to the tree, we need to remove it now, since it was not originally in the tree.
if(added == true) {
remove(k);
added = false;
}
return dataValue;
}
And the searchTreeNode method used in put and remove:
private BinaryNode searchTreeNode(BinaryNode r, Pair k) {
BinaryNode tempNode = r; //duplicates the root node.
BinaryNode prev = r.getParent();
if(tempNode.isLeaf()) {
return tempNode;
} else {
if(tempNode.getData().getKey().compareTo(k) == 0) {
return tempNode;
} else if(tempNode.getData().getKey().compareTo(k) == 1) {
return searchTreeNode(tempNode.getLeft(), k);
} else {
return searchTreeNode(tempNode.getRight(), k);
}
}
}
I don't really know why I get the nullPointerException error in the remove method and not really sure why successor method fails either.
Edit
Code for BinaryNode getParent method along with the constructor:
public BinaryNode(Record value, BinaryNode left, BinaryNode right, BinaryNode parent) {
recordValue = value; //Initializes the Record object.
leftNode = left; //Initializes the left child of this node.
rightNode = right; //Initializes the right child of this node.
parentNode = parent; //Initializes the parent of this node.
}
public BinaryNode() {
//Initializes all the variable to null.
recordValue = null;
leftNode = null;
rightNode = null;
parentNode = null;
}
public BinaryNode getParent() {
return parentNode;
}

inorder iterator for binary tree - java

Here is my Node class:
private class Node {
private int key; // the key field
private Object data; // the rest of the data item
private Node left; // reference to the left child/subtree
private Node right; // reference to the right child/subtree
private Node parent; // reference to the parent
.. and so on.
This is the inorder iterator with next() and hasNext() methods:
private class inorderIterator implements LinkedTreeIterator {
private Node nextNode;
private inorderIterator() {
// The traversal starts with the root node.
nextNode = root;
if(nextNode == null)
return;
while (nextNode.left != null)
nextNode = nextNode.left;
}
public boolean hasNext() {
return (nextNode != null);
}
public int next() {
if(!hasNext())
throw new NoSuchElementException();
Node r = nextNode;
if (nextNode.right != null) {
nextNode = nextNode.right;
while (nextNode.left != null) {
nextNode = nextNode.left;
}
return r.key;
} else while (true) {
if (nextNode.parent == null) {
nextNode = null;
return r.key;
}
if (nextNode.parent.left == nextNode) {
nextNode = nextNode.parent;
return r.key;
}
nextNode = nextNode.parent;
}
return r.key;
}
}
The problem is, it only ever prints the left nodes on the left sub-tree.
For example, for a tree with root node 17, left node 15 and right node 19, it only prints 15.
So it never enters a right subtree.
I'm guessing the problem is with the else while (true) portion, but I can't figure out how to fix this.
You could try a recursive approach.
Something like:
public void printTreeInOrder(Node node){
if(node.left != null){
printTree(node.left);
}
System.out.println(node.key);
if(node.right != null){
printTree(node.right);
}
}
If you passed this method the root node it should print out the entire tree for you.
I hope this helps.
Best.
Turns out that the parent field of my nodes was not being updated properly. Once that was fixed, the iterator worked properly.
I would use a stack with this helper method:
Node advance_to_min(Node r)
{
while (r.left != null)
{
s.push(r);
r = r.left;
}
return r;
}
The first node inorder is given by the call to this method on the root. Something like:
curr = advance_to_min(curr);
And then I would implement next() thus:
void next()
{
curr = curr.right;
if (curr != null)
{
curr = advance_to_min(curr);
return;
}
if (s.is_empty())
curr = null;
else
curr = s.pop();
}
curr and the stack s would be iterator attributes. curr would point to the current node in the inorder sequence.
The cost O(lg n) at worst case for each next() call (if the tree tends to be balanced) and the approach does not require parent pointers; so, it would have the same space cost than using parent pointers but only in the worst case

Recursive Insert for Binary Tree

I'm working on code for insertion into a binary search tree. It works for the first node I insert, making it the root, but after that it doesn't seem to insert any nodes. I'm sure it's a problem with setting left/right references, but I can't quite figure it out. Please help!
//params: key of node to be inserted, parent node
public void insert(int newKey, TreeNode parent){
//if the root of the tree is empty, insert at root
if(this.getRoot() == null){
this.root = new TreeNode(newKey, null, null);
}
//if the node is null, insert at this node
else if(parent == null)
parent = new TreeNode(newKey, null, null);
else{
//if the value is less than the value of the current node, call insert on the node's left child
if(newKey < parent.getKey()) {
insert(newKey, parent.getLeft());
}
//greater than value of current node, call insert on node's right child
else if(newKey > parent.getKey()){
insert(newKey, parent.getRight());
}
//same as value of current node, increment iteration field by one
else if(newKey == parent.getKey())
parent.incrementIterations();
}
}
My treenodes have key, left, right, and iteration fields, as well as getter/setter functions.
Thank you in advance!
public Node insertNode(Node head, int data) {
if(head == null){
head = new Node();
head.data = data;
return head;
}
if(head.data < data) {
head.right = insertNode(head.right,data);
} else {
head.left = insertNode(head.left, data);
}
return head;
}
If (parent==null) you are creating a node, but you are not associating it to tree back. Its just created and garbage collected.
You should be using insert (newkey, parent) then u still have handle to tree
private AVLNode insert(AVLNode root, int value){
if (root == null) return new AVLNode(value);
if(root.value > value)
root.leftChild = insert(root.rightChild, value);
else
root.rightChild = insert(root.leftChild, value);
return root;
}

Converting an ordered binary tree to a doubly circular link list

I have a ordered binary tree:
4
|
|-------|
2 5
|
|-------|
1 3
The leaves point to null. I have to create a doubly link list which should look like
1<->2<->3<->4<->5
(Obviously 5 should point to 1)
The node class is as follows:
class Node {
Node left;
Node right;
int value;
public Node(int value)
{
this.value = value;
left = null;
right = null;
}
}
As you can see the doubly link list is ordered (sorted) as well.
Question: I have to create the linked list form the tree without using any extra pointers. The left pointer of the tree should be the previous pointer of the list and the right pointer of the tree should be the next pointer of the list.
What I thought off: Since the tree is an ordered tree, the inorder traversal would give me a sorted list. But while doing the inorder traversal I am not able to see, where and how to move the pointers to form a doubly linked list.
P.S I checked some variations of this question but none of them gave me any clues.
It sounds like you need a method that accepts a Node reference to the root of the tree and returns a Node reference to the head of a circular list, where no new Node objects are created. I would approach this recursively, starting with the simple tree:
2
|
|-----|
1 3
You don't say whether the tree is guaranteed to be full, so we need to allow for 1 and/or 3 being null. The following method should work for this simple tree:
Node simpleTreeToList(Node root) {
if (root == null) {
return null;
}
Node left = root.left;
Node right = root.right;
Node head;
if (left == null) {
head = root;
} else {
head = left;
left.right = root;
// root.left is already correct
}
if (right == null) {
head.left = root;
root.right = head;
} else {
head.left = right;
right.right = head;
right.left = root;
}
return head;
}
Once it is clear how this works, it isn't too hard to generalize it to a recursive method that works for any tree. It is a very similar method:
Node treeToList(Node root) {
if (root == null) {
return null;
}
Node leftTree = treeToList(root.left);
Node rightTree = treeToList(root.right);
Node head;
if (leftTree == null) {
head = root;
} else {
head = leftTree;
leftTree.left.right = root;
root.left = leftTree.left;
}
if (rightTree == null) {
head.left = root;
root.right = head;
} else {
head.left = rightTree.left;
rightTree.left.right = head;
rightTree.left = root;
root.right = rightTree;
}
return head;
}
If I got all the link assignments covered correctly, this should be all you need.
Do an in-order traversal of the list, adding each list item to the doubly linked list as you encounter it. When done, add an explicit link between the first and last items.
Update 3/6/2012: Since you must reuse the Node objects you already have, after you put the node objects into the the list, you can then iterate over the list and reset the left and right pointers of the Node objects to point to their siblings. Once that is done, you can get rid of the list and simply return the first node object.
This should also work:
NodeLL first = null;
NodeLL last = null;
private void convertToLL(NodeBST root) {
if (root == null) {
return;
}
NodeLL newNode = new NodeLL(root.data);
convertToLL(root.left);
final NodeLL l = last;
last = newNode;
if (l == null)
first = newNode;
else {
l.next = newNode;
last.prev = l;
}
convertToLL(root.right);
}
Let your recursion return the left and right end of formed list. Then you link your current node to the last of the left list, and first of the right list. Basic case it, when there is no left or right element, which is the node it self for both. Once all is done, you can link the first and last of the final result. Below is the java code.
static void convertToSortedList(TreeNode T){
TreeNode[] r = convertToSortedListHelper(T);
r[1].next = r[0];
r[0].prev= r[1];
}
static TreeNode[] convertToSortedListHelper(TreeNode T){
TreeNode[] ret = new TreeNode[2];
if (T == null) return ret;
if (T.left == null && T.right == null){
ret[0] = T;
ret[1] = T;
return ret;
}
TreeNode[] left = TreeNode.convertToSortedListHelper(T.left);
TreeNode[] right = TreeNode.convertToSortedListHelper(T.right);
if (left[1] != null) left[1].next = T;
T.prev = left[1];
T.next = right[0];
if (right[0] != null) right[0].prev = T;
ret[0] = left[0]==null? T:left[0];
ret[1] = right[1]==null? T:right[1];
return ret;
}
Add the following method to your Node class
public Node toLinked() {
Node leftmost = this, rightmost = this;
if (right != null) {
right = right.toLinked();
rightmost = right.left;
right.left = this;
}
if (left != null) {
leftmost = left.toLinked();
left = leftmost.left;
left.right = this;
}
leftmost.left = rightmost;
rightmost.right = leftmost;
return leftmost;
}
EDIT By maintaining the invariant that the list returned by toLinked() has the proper form, you can easily get the left- and rightmost nodes in the sublist returned by the recursive call on the subtrees
/* input: root of BST. Output: first node of a doubly linked sorted circular list. **Constraints**: do it in-place. */
public static Node transform(Node root){
if(root == null){
return null;
}
if(root.isLeaf()){
root.setRight(root);
root.setLeft(root);
return root;
}
Node firstLeft = transform(root.getLeft());
Node firstRight = transform(root.getRight());
Node lastLeft = firstLeft == null ? null : firstLeft.getLeft();
Node lastRight= firstRight == null ? null : firstRight.getLeft();
if(firstLeft != null){
lastLeft.setRight(root);
root.setLeft(lastLeft);
if(lastRight == null){
firstLeft.setLeft(root);
}
else{
firstLeft.setLeft(lastRight);
root.setRight(firstRight);
}
}
if(firstRight != null){
root.setRight(firstRight);
firstRight.setLeft(root);
if(lastLeft == null){
root.setLeft(lastRight);
lastRight.setLeft(root);
firstLeft = root;
}
else{
root.setLeft(lastLeft);
lastRight.setRight(firstLeft);
}
}
return firstLeft;
}

Categories