I'm working on Binary Search Trees, and currently working on recursive delete method. I have a bug in my code; it deletes nodes with no children and with one-child. Problem arises when trying to delete node with two children. (Point of reference - I am replacing deleted node with smallest node in Right Subtree)
My code is:
//Driver
public void delete (String val){
root = delete(root, val);
}
//Recursive Delete Method
private static StringNode delete(StringNode node, String v){
StringNode temp;
if(node == null){
return null;
}
if(v.compareTo(node.getString()) < 0){
node.setLeft(delete(node.getLeft(), v));
}
else if(v.compareTo(node.getString()) > 0){
node.setRight(delete(node.getRight(), v));
}
else{
if(node.getLeft() == null){
node = node.getRight();
}
else if(node.getRight() == null){
node = node.getLeft();
}
else{
node = node.getRight();
while(node.getLeft() != null){
node = node.getLeft();
}
node.setRight(delete(node, node.getString()));
}
}
return node;
}
I have debugged and see that I lose a child when re-connecting the nodes after deletion. But I don't know how to correct in my code.
I figured out the bug. I separated the delete method into delete and deleteNode methods. Worked out.
Related
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;
}
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.
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.
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;
}
I am implementing my own linked list in Java. The node class merely has a string field called "name" and a node called "link". Right now I have a test driver class that only inserts several names sequentially. Now, I am trying to write a sorting method to order the nodes alphabetically, but am having a bit of trouble with it. I found this pseudocode of a bubblesort from someone else's post and tried to implement it, but it doesn't fully sort the entries. I'm not really quite sure why. Any suggestions are appreciated!
private void sort()
{
//Enter loop only if there are elements in list
boolean swapped = (head != null);
// Only continue loop if a swap is made
while (swapped)
{
swapped = false;
// Maintain pointers
Node curr = head;
Node next = curr.link;
Node prev = null;
// Cannot swap last element with its next
while (next != null)
{
// swap if items in wrong order
if (curr.name.compareTo(next.name) < 0)
{
// notify loop to do one more pass
swapped = true;
// swap elements (swapping head in special case
if (curr == head)
{
head = next;
Node temp = next.link;
next.link = curr;
curr.link = temp;
curr = head;
}
else
{
prev.link = curr.link;
curr.link = next.link;
next.link = curr;
curr = next;
}
}
// move to next element
prev = curr;
curr = curr.link;
next = curr.link;
}
}
}
I spent some minutes eyeballing your code for errors but found none.
I'd say until someone smarter or more hard working comes along you should try debugging this on your own. If you have an IDE like Eclipse you can single-step through the code while watching the variables' values; if not, you can insert print statements in a few places and hand-check what you see with what you expected.
UPDATE I
I copied your code and tested it. Apart from the fact that it sorts in descending order (which may not be what you intended) it worked perfectly for a sample of 0, 1 and 10 random nodes. So where's the problem?
UPDATE II
Still guessing what could be meant by "it doesn't fully sort the entries." It's possible that you're expecting lexicographic sorting (i.e. 'a' before 'B'), and that's not coming out as planned for words with mixed upper/lower case. The solution in this case is to use the String method compareToIgnoreCase(String str).
This may not be the solution you're looking for, but it's nice and simple. Maybe you're lazy like I am.
Since your nodes contain only a single item of data, you don't really need to re-shuffle your nodes; you could simply exchange the values on the nodes while leaving the list's structure itself undisturbed.
That way, you're free to implement Bubble Sort quite simply.
you should use the sorting procedures supplied by the language.
try this tutorial.
Basically, you need your element class to implement java.lang.Comparable, in which you will just delegate to obj.name.compareTo(other.name)
you can then use Collections.sort(yourCollection)
alternatively you can create a java.util.Comparator that knows how to compare your objects
To obtain good performance you can use Merge Sort.
Its time complexity is O(n*log(n)) and can be implemented without memory overhead for lists.
Bubble sort is not good sorting approach. You can read the What is a bubble sort good for? for details.
This may be a little too late. I would build the list by inserting everything in order to begin with because sorting a linked list is not fun.
I'm positive your teacher or professor doesn't want you using java's native library. However that being said, there is no real fast way to resort this list.
You could read all the nodes in the order that they are in and store them into an array. Sort the array and then relink the nodes back up. I think the Big-Oh complexity of this would be O(n^2) so in reality a bubble sort with a linked list is sufficient
I have done merge sort on the singly linked list and below is the code.
public class SortLinkedList {
public static Node sortLinkedList(Node node) {
if (node == null || node.next == null) {
return node;
}
Node fast = node;
Node mid = node;
Node midPrev = node;
while (fast != null && fast.next != null) {
fast = fast.next.next;
midPrev = mid;
mid = mid.next;
}
midPrev.next = null;
Node node1 = sortLinkedList(node);
Node node2 = sortLinkedList(mid);
Node result = mergeTwoSortedLinkedLists(node1, node2);
return result;
}
public static Node mergeTwoSortedLinkedLists(Node node1, Node node2) {
if (null == node1 && node2 != null) {
return node2;
} else if (null == node2 && node1 != null) {
return node1;
} else if (null == node1 && null == node2) {
return null;
} else {
Node result = node1.data <= node2.data ? node1 : node2;
Node prev1 = null;
while (node1 != null && node2 != null) {
if (node1.data <= node2.data) {
prev1 = node1;
node1 = node1.next;
} else {
Node next2 = node2.next;
node2.next = node1;
if (prev1 != null) {
prev1.next = node2;
}
node1 = node2;
node2 = next2;
}
}
if (node1 == null && node2 != null) {
prev1.next = node2;
}
return result;
}
}
public static void traverseNode(Node node) {
while (node != null) {
System.out.print(node + " ");
node = node.next;
}
System.out.println();
}
public static void main(String[] args) {
MyLinkedList ll1 = new MyLinkedList();
ll1.insertAtEnd(10);
ll1.insertAtEnd(2);
ll1.insertAtEnd(20);
ll1.insertAtEnd(4);
ll1.insertAtEnd(9);
ll1.insertAtEnd(7);
ll1.insertAtEnd(15);
ll1.insertAtEnd(-3);
System.out.print("list: ");
ll1.traverse();
System.out.println();
traverseNode(sortLinkedList(ll1.start));
}
}
The Node class:
public class Node {
int data;
Node next;
public Node() {
data = 0;
next = null;
}
public Node(int data) {
this.data = data;
}
public int getData() {
return this.data;
}
public Node getNext() {
return this.next;
}
public void setData(int data) {
this.data = data;
}
public void setNext(Node next) {
this.next = next;
}
#Override
public String toString() {
return "[ " + data + " ]";
}
}
The MyLinkedList class:
public class MyLinkedList {
Node start;
public void insertAtEnd(int data) {
Node newNode = new Node(data);
if (start == null) {
start = newNode;
return;
}
Node traverse = start;
while (traverse.getNext() != null) {
traverse = traverse.getNext();
}
traverse.setNext(newNode);
}
public void traverse() {
if (start == null)
System.out.println("List is empty");
else {
Node tempNode = start;
do {
System.out.print(tempNode.getData() + " ");
tempNode = tempNode.getNext();
} while (tempNode != null);
System.out.println();
}
}
}