So I have a binary tree with data and I have currently written a remove method for the binary tree that should remove a node while still maintaining the binary tree as a balanced tree.
Currently I am doing the remove like this:
public Node remove(K key) {
return removeHelper(key, root, null);
}
public Node removeHelper(K key, Node targetNode, Node parent) {
if (targetNode == null) {
return targetNode;
} else {
if (key.compareTo(targetNode.key) == 0) {
// we have found the item we are looking for!
// CASE #1 - The target node does not have any children
if (targetNode.left == null && targetNode.right == null) {
if (parent != null) {
if (parent.left.equals(targetNode)) {
parent.left = null;
} else if (parent.right.equals(targetNode)) {
parent.right = null;
}
}
// CASE #2. target node only has a one child, right or left.
} else if (targetNode.left == null) {
targetNode = targetNode.right;
} else if (targetNode.right == null) {
targetNode = targetNode.left;
// CASE #3 - It has 2 children.
} else {
Node temp = targetNode;
Node rightMin = FindMin(temp.right);
targetNode.key = rightMin.key;
targetNode.value = rightMin.value;
}
} else if (key.compareTo(targetNode.key) < 0) {
return removeHelper(key, targetNode.left, targetNode);
} else if (key.compareTo(targetNode.key) > 0) {
return removeHelper(key, targetNode.right, targetNode);
} else {
return targetNode;
}
}
return targetNode;
}
and here is the FindMin method:
//Finding the minimum node in this subtree passed in
private Node FindMin(Node rootNode) {
if (rootNode.left == null) {
return rootNode;
} else {
return FindMin(rootNode.left);
}
}
And then I am trying to test the removal of nodes like such:
BinarySearchTree<Integer, String> tree = new BinarySearchTree<Integer, String>();
tree.put(40, "Forty");
tree.put(20, "Twenty");
tree.put(60, "Sixty");
tree.put(10, "Ten");
tree.put(30, "Thirty");
tree.put(50, "Fifty");
tree.put(70, "Seventy");
tree.put(4, "four");
tree.remove(70);
tree.remove(60);
System.out.println(tree);
And the output from this is:
(4:four)(10:Ten)(20:Twenty)(30:Thirty)(40:Forty)(50:Fifty)(60:Sixty)
As you can see, the 70 is being remove successfully but the 60 is not being removed for some reason. I tried changing around my code a bit but I usually run into a stackoverflow error when doing so.
Anyone see an issue or case I am missing here?
Related
Could you tell me why this code wont delete a node in a BST? Is there any logical error in my code?
// To delete a node from the BST
public Node deleteNode(Node myRoot, int toDel) {
if (myRoot == null) return null;
else if (toDel < myRoot.data) myRoot.left = deleteNode(myRoot.left, toDel);
else if (toDel > myRoot.data) myRoot.right = deleteNode(myRoot.right, toDel);
else {
// Leaf node
if (myRoot.right == null && myRoot.left == null) {
myRoot = null;
} else if (myRoot.left == null) { // No left child
myRoot = myRoot.right;
} else if (myRoot.right==null){ // No right child
myRoot = myRoot.left;
}
}
return myRoot;
}
NOTE :- This code only deletes the nodes with one child or no child. I am currently working on deleting a node with 2 children so please dont solve that for me.
If 0 children, simply delete node (return null for it).
If there is 1 child, simply replace the node with the child that is not null.
public Node deleteNode(Node myRoot, int toDel) {
if (myRoot == null) {
return null;
} else if (myRoot.data == toDel) {
if (myRoot.left != null) {
return myRoot.left;
} else if (myRoot.right != null) {
return myRoot.right;
} else {
return null;
}
}
...
return myRoot;
}
so currently I’m trying to follow a tutorial from FreeCodeCamp on implementing a Binary tree, but I’m having trouble with adding to and traversing through my tree.
For some reason, it seems that I’m able to add nodes to my tree, but when I try to traverse through my tree via iterative preorder traversal, it only picks up my root node. Its as if my nodes aren’t pointing to each other.
I have a feeling that the problem either lies with my add method or my traversal method, both of which are below. Any help would be greatly appreciated.
Add method:
public boolean add(T thing)
{
if(contains(thing))
{
return false;
} else {
root = add(root,thing);
count++;
return true;
}
}
private Node add(Node node,T thing)
{
if(node == null)
{
node = new Node(thing,null,null);
} else
{
if(thing.compareTo(node.value) <0)
{
if(node.left == null)
{
node.left = node = new Node(thing,null,null);
} else{
node.left =add(node.left,thing);
}
}
else
{
if(node.right == null)
{
node.right = node = new Node(thing,null,null);
}else {
node.right = add(node.right,thing);
}
}
}
return node;
}
Traversal:
public void traverse()
{
preorder(root);
}
private void preorder(Node node)
{ int iteration=0;
java.util.Stack<Node> stack = new java.util.Stack<Node>();
System.out.println( "root is: " +node.value);
stack.push(node);
while(stack.empty() == false)
{
Node current = stack.pop();
System.out.println("in preorder: "+current.value);
if(current.right != null)
{
stack.push(current.right);
}
if(current.left != null)
{
stack.push(current.left);
}
iteration++;
}
System.out.println("iteration: "+iteration);
}
You are not traversing your tree while adding in the tree. Check my tree insert method to get the idea:-
void insert(Node temp,int value) {
if(temp==null){
temp=new Node(value,null,null);
this.root=temp;
}
else{
Queue<Node> q = new LinkedList<>();
q.add(temp);
while (!q.isEmpty()) {
temp = q.peek();
q.remove();
if (temp.left == null) {
temp.left = new Node(value, null, null);
break;
} else
q.add(temp.left);
if (temp.right == null) {
temp.right =new Node(value, null, null);
break;
} else
q.add(temp.right);
}
}
}
I have this method that uses recursion to find a node that holds a specified String in a binary tree. The issue is that it returns null, when it should return the node that holds the specified name, and I'm not sure why.
Here's the method:
public Node getNode(Node currentNode, String name) {
Node retrieved = null;
if (currentNode.getName().equals(name)) { retrieved = currentNode; }
else
{
if (currentNode.right != null) {
getNode(currentNode.right, name);
}
if (currentNode.left != null) {
getNode(currentNode.left, name);
}
}
return retrieved;
}
Any insight into what may be the problem would be appreciated.
You need to capture the return value of your two recursive calls. Otherwise you're doing recursion "for nothing" and throwing away the result of the recursion.
public Node getNode(Node currentNode, String name){
Node retrieved = null;
if (currentNode.getName().equals(name)) { retrieved = currentNode; }
else
{
if (currentNode.right != null){
retrieved = getNode(currentNode.right, name);
}
if (retrieved == null && currentNode.left != null){
retrieved = getNode(currentNode.left, name);
}
}
return retrieved;
}
The following solution is arguably better style because you leave null checks for a base case. Notice how you no longer need to check currentNode.right != null or currentNode.left != null, as they're covered by the base case after one more recursive step.
public static Node getNode(Node currentNode, String name){
// Base case: currentNode is null, nothing left to search
if (currentNode == null) {
return null;
}
Node retrieved = null;
if (currentNode.getName().equals(name)) {
retrieved = currentNode;
} else {
// Try to search right subtree
retrieved = getNode(currentNode.right, name);
// If not found in right subtree, then search left subtree
if (retrieved == null){
retrieved = getNode(currentNode.left, name);
}
}
return retrieved;
}
Solution
getNode(currentNode.right, name);
You call the getNode(...) method but you don't do anything with it.
A better solution
If you are willing to use googles Guava (must-have for every project in my opinion) and java 8, you can do the following:
public static final Traverser<Node> TREE_TRAVERSER =
Traverser.forTree((SuccessorsFunction<Node>) node ->
Stream.of(node.right, node.left)
.filter(Objects::nonNull)
.collect(Collectors.toList()));
And then call it where ever you want to traverse the tree:
for (Node n : TREE_TRAVERSER.depthFirstPreOrder(root)) {
if (n.getName().equals("foo")) {
// todo: do stuff with node foo
}
}
The java 8 way of traversing the tree would then be:
Iterable<Node> nodes = TREE_TRAVERSER.depthFirstPreOrder(root);
Optional<Node> result = StreamSupport.stream(nodes.spliterator(), false)
.filter(n -> n.getName().equals("foo")) // find node with name "foo"
.findAny(); // we assume there is <= 1 node, so we take any.
// node.isPresent() to check if you found a Node and result.get() to get the Node
How does this work?
Well, Guava has this nice class called a Traverser<N>. You just give it one parameter, which is the SuccessorsFunction<N>. It takes any object N and returns a Iterable<? extends N>, which are the child nodes.
We use Streams to do this. First we create a Stream of the two child nodes. We then filter them to only have a Stream of nonNull Nodes and collect them in a List (since the SuccessorsFunction<Node> wants to return a Iterable<Node>).
This Traverser<N> only has to be created once, so we made it public static final. You can now choose an iteration order. We chose depthFirstPreOrder, which returns an Iterable<N> we can iterate over
If you haven't heard of Streams before, I would recommend this turorial.
I would suggest taking tail recursions into account, since performance-wise this is a major factor :
public static Node getNode(Node currentNode, String name){
// Base case: currentNode is null, nothing left to search
if (currentNode == null) {
return null;
}
Node retrieved = null;
if (currentNode.name.equals(name)) {
return currentNode;
} else {
// Tail recursions
if(currentNode.left == null) {
return getNode(currentNode.right, name);
}
else if(currentNode.right == null) {
return getNode(currentNode.left, name);
}
// Non Tail recursion
else {
retrieved = getNode(currentNode.left, name);
// If not found in left subtree, then search right subtree
if (retrieved == null){
retrieved = getNode(currentNode.right, name);
}
}
}
return retrieved;
}
Attached is the full code which was executed on an online compiler:
public class MyClass {
static class Node {
public String name;
public Node left;
public Node right;
Node(String name) {
this.name = name;
right = null;
left = null;
}
#Override
public String toString() {
return "name = " + name + " hasLeft = " + (left != null) + " hasRight = " + (right != null);
}
}
static class Tree {
Node root;
public Node getRoot() {
return root;
}
private Node addRecursive(Node current, String value) {
if (current == null) {
return new Node(value);
}
if (value.compareTo(current.name) < 0) {
current.left = addRecursive(current.left, value);
} else if (value.compareTo(current.name) > 0) {
current.right = addRecursive(current.right, value);
} else {
// value already exists
return current;
}
return current;
}
public Tree add(String value) {
root = addRecursive(root, value);
return this;
}
public void traverseInOrder(Node node) {
if (node != null) {
traverseInOrder(node.left);
System.out.print(" " + node.name);
traverseInOrder(node.right);
}
}
public void traverseInOrder() {
traverseInOrder(root);
System.out.println("");
}
}
public static void main(String args[]) {
Tree tree = new Tree();
tree.add("a").add("ab").add("bbb").add("cc").add("zolko").add("polip").traverseInOrder();
Node found = getNode(tree.getRoot(),"vv");
System.out.println(found);
found = getNode(tree.getRoot(),"ab");
System.out.println(found);
found = getNode(tree.getRoot(),"polip");
System.out.println(found);
found = getNode(tree.getRoot(),"java");
System.out.println(found);
found = getNode(tree.getRoot(),"zolko");
System.out.println(found);
}
public static Node getNode(Node currentNode, String name){
// Base case: currentNode is null, nothing left to search
if (currentNode == null) {
return null;
}
Node retrieved = null;
if (currentNode.name.equals(name)) {
return currentNode;
} else {
// Tail recursions
if(currentNode.left == null) {
return getNode(currentNode.right, name);
}
else if(currentNode.right == null) {
return getNode(currentNode.left, name);
}
// Non Tail recursion
else {
retrieved = getNode(currentNode.left, name);
// If not found in left subtree, then search right subtree
if (retrieved == null){
retrieved = getNode(currentNode.right, name);
}
}
}
return retrieved;
}
}
And the outputs of the main method execution:
a ab bbb cc polip zolko
null
name = ab hasLeft = false hasRight = true
name = polip hasLeft = false hasRight = false
null
name = zolko hasLeft = true hasRight = false
I implemented recursive algorihtm for deleting nodes in BST, but it seems not to work properly in case in which the node to be deleted has two children. Here is a code for method used to delete nodes:
public boolean delete(int val)
{
Node nodeToBeDeleted = find(val);
if(nodeToBeDeleted != null)
{
//case 1: node has no children
if(nodeToBeDeleted.leftChild == null && nodeToBeDeleted.rightChild == null)
deleteCase1(nodeToBeDeleted);
//case 3: node has two children
else if(nodeToBeDeleted.leftChild != null && nodeToBeDeleted.rightChild != null)
{
deleteCase3(nodeToBeDeleted);
}
//case 2: node has one child
else if(nodeToBeDeleted.leftChild != null)
{
//case 2 where left child should be deleted
deleteCase2(nodeToBeDeleted);
}
else if(nodeToBeDeleted.rightChild != null)
{
//case 2 where right child should be deleted
deleteCase2(nodeToBeDeleted);
}
return true;
}
else
return false;
}
And here deleteCase1, deleteCase2 and deleteCase3 methods:
private void deleteCase1(Node nodeToBeDeleted)
{
//check if node to be deleted is a left or a right child of the parent of the node to be deleted
if(nodeToBeDeleted.parent.leftChild == nodeToBeDeleted)
{
nodeToBeDeleted.parent.leftChild = null;
}
else if(nodeToBeDeleted.parent.rightChild == nodeToBeDeleted)
{
nodeToBeDeleted.parent.rightChild = null;
}
}
Here find method:
public Node find(int val)
{
if(root != null)
{
return findNode(root, new Node(val));
}
return null;
}
private Node findNode(Node search, Node node)
{
if(search == null)
return null;
if(search.data == node.data)
{
return search;
}
else
{
Node returnNode = findNode(search.leftChild, node);
if(returnNode == null)
{
returnNode = findNode(search.rightChild, node);
}
return returnNode;
}
}
minLeftTreversal method:
private Node minLeftTreversal(Node node)
{
if(node.leftChild == null)
return node;
return minLeftTreversal(node.leftChild);
}
Structure of the tree looks like this:
enter image description here
Algorithm works if I delete 75, but if I try to delete 25 it messes up.
Thank you in advance!
Your first if statement in public boolean delete(int val) is missing the { and }
//case 1: node has no children
if(nodeToBeDeleted.leftChild == null && nodeToBeDeleted.rightChild == null)
{ // <---- ADD THIS
deleteCase1(nodeToBeDeleted);
} // <---- AND ADD THIS
//case 3: node has two children
else if(nodeToBeDeleted.leftChild != null && nodeToBeDeleted.rightChild != null)
{
deleteCase3(nodeToBeDeleted);
}
Iterator words = treeSearch.getItems().iterator();
int addCount = 0;
while (words.hasNext())
{
numWords++;
rootNode = add(objectToReference, addCount++, (ITreeSearch) words.next(), 0, rootNode);
}
//Add to the Tree
private TernaryTreeNode add(Object storedObject, int wordNum, ITreeSearch treeSearch, int pos, TernaryTreeNode parentNode) throws NoSearchValueSetException
{
if (parentNode == null)
{
parentNode = new TernaryTreeNode(treeSearch.getNodeValue(pos));
}
if (parentNode.lessThan(treeSearch, pos))
{
parentNode.left = add(storedObject, wordNum, treeSearch, pos, parentNode.left);
}
else if (parentNode.greaterThan(treeSearch, pos))
{
parentNode.right = add(storedObject, wordNum, treeSearch, pos, parentNode.right);
}
else
{
if (pos < treeSearch.getNumberNodeValues())
{
parentNode.mid = add(storedObject, wordNum, treeSearch, pos + 1, parentNode.mid);
}
else
{
numberOfObjectsStored++;
parentNode.addStoredData(storedObject);
}
}
return parentNode;
}
This a snippet of my code in my Ternary Tree which I use for inserting a Name of a person(can hav multiple words in a name, like Michele Adams, Tina Joseph George, etc). I want to convert the above recursion to a for loop / while iterator.
Please guide me on this.
General idea in replacing recursion with iteration is to create a state variable, and update it in the loop by following the same rules that you follow in your recursive program. This means that when you pick a left subtree in the recursive program, you update the state to reference the left subtree; when you go to the right subtree, the state changes to reference the right subtree, and so on.
Here is an example of how to rewrite the classic insertion into binary tree without recursion:
public TreeNode add(TreeNode node, int value) {
// Prepare the node that we will eventually insert
TreeNode insert = new TreeNode();
insert.data = value;
// If the parent is null, insert becomes the new parent
if (node == null) {
return insert;
}
// Use current to traverse the tree to the point of insertion
TreeNode current = node;
// Here, current represents the state
while (true) {
// The conditional below will move the state to the left node
// or to the right node, depending on the current state
if (value < current.data) {
if (current.left == null) {
current.left = insert;
break;
} else {
current = current.left;
}
} else {
if (current.right == null) {
current.right = insert;
break;
} else {
current = current.right;
}
}
}
// This is the original node, not the current state
return node;
}
Demo.
Thanks dasblinkenlight..
This is my logic for replacing the above recursive function for a ternary tree.
Iterator words = treeSearch.getItems().iterator();
while (words.hasNext())
{
for (int i = 0; i < word.getNumberNodeValues(); i++)
{
add_Non_Recursive(objectToReference, word, i);
}
}
//Add to Tree
private void add_Non_Recursive(Object storedObject, ITreeSearch treeSearch, int pos) throws NoSearchValueSetException
{
TernaryTreeNode currentNode = rootNode;
// Start from a node(parentNode). If there is no node, then we create a new node to insert into the tree.
// This could even be the root node.
if (rootNode == null)
{
rootNode = new TernaryTreeNode(treeSearch.getNodeValue(pos));
}
else
{
while (currentNode != null)
{
if (currentNode.lessThan(treeSearch, pos))
{
if (currentNode.left == null)
{
currentNode.left = new TernaryTreeNode(treeSearch.getNodeValue(pos));
currentNode = null;
}
else
{
currentNode = currentNode.left;
}
}
else if (currentNode.greaterThan(treeSearch, pos))
{
if (currentNode.right == null)
{
currentNode.right = new TernaryTreeNode(treeSearch.getNodeValue(pos));
currentNode = null;
}
else
{
currentNode = currentNode.right;
}
}
else
{
if (currentNode.mid == null)
{
currentNode.mid = new TernaryTreeNode(treeSearch.getNodeValue(pos));
currentNode = null;
}
else
{
currentNode = currentNode.mid;
}
}
}
}
}
But I dropped this logic as it wasnt great in performing, it took more time than the recursive counterpart.