So I want to go into my tree (which is assumed to have no duplicates and is branched correctly) and find the element that is given in the parameters. I have found that my method gives me a BinaryNode that resembles what I want (the root) in its fields, but is not actually the root. I have not overridden the equals method. Using the equals method, the test returns false when the returned object and the root are compared. I want to know why my variable, elementNode, does not reference (and hence change) the root to be null when it is set null.
Binary nodes are implemented with generics. This method is being called with the root as its starting point. Any help will be appreciated, thank you.
/**
* Returns the node that the sought element resides within
*
* #param element: The element being hunted
* #param start: The start of the search (usually the root)
* #return The node that the element resides in
*/
private BinaryNode<T> findElementNode(T element, BinaryNode<T> start) {
if (start.getElement().equals(element)) {
return start;
}
// the element is not in the collection
if (start.getLeftChild() == null && start.getRightChild() == null) {
return null;
}
int comparison = element.compareTo(start.getElement());
if (comparison < 0) {
return findElementNode(element, start.getLeftChild());
} else {
return findElementNode(element, start.getRightChild());
}
}
EDIT FOR EXAMPLE: (this is for a removal method)
if (!hasLeft && !hasRight) {
System.out.println(elementNode + "," + root);
elementNode = null;
System.out.println(elementNode + "," + root);
return true;
}
This outputs:
BinaryNode#68b0019f,BinaryNode#68b0019f and null,BinaryNode#68b0019f
EDIT FOR ANSWER: The reason that the returned element does not set the node it points to as null is because in Java, we can only point at, not edit, memory locations. So in order to make my node null, I will locate the parent and just set its left/right child to null.
Try with something like this.
private boolean findElementNode(T element, BinaryNode<T> start) {
if (start == null) {
return false;
} else {
if (element.getElement().equals(start.getElement())) {
return true;
} else {
int comparison = element.compareTo(start.getElement());
if (comparison < 0) {
return findElementNode(element, start.getLeftChild());
} else {
return findElementNode(element, start.getRightChild());
}
}
}
EDIT: this is actually what you want. Tell me if this works.
private BinaryNode<T> findElementNode(T element, BinaryNode<T> start) {
if(start != null){
if(start.getElement().equals(element)){
return start;
} else {
BinaryNode<T> start = findElementNode(element, start.getLeftChild());
if(start == null) {
start = findElementNode(element, start.getRightChild());
}
return start;
}
} else {
return null;
}
}
Related
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 created the following Method to search for a certain ParentReference Id in a Tree that is unsorted and where every node can have any number of children. If the given parentRef matches the Node's parentRef, the Node should be returned.
public static <T>Node<T> search(Node<T> node, int parentRef) {
if(node.getParentRef() == parentRef){
return node;
}
if(node.getChildren()!= null){
for(int i = 0; i < node.getChildren().size(); i++){
if(node.getChildren().get(i).parentRef == parentRef){
return node;
}
else {
search(node.getChildren().get(i), parentRef);
}
}
}
return null;
}
However, it does not work and always returns null but I don't know why. Can anybody explain what I am doing wrong?
In the else branch, you call search recursively, but don't return its value, so it is lost. You should check if it's not null, and if so, return it:
else {
Node<T> result = search(node.getChildren().get(i), parentRef);
if (result != null) {
return result;
}
}
Okay so I've been looking into this for days and everytime I think I've gotten it down I start writing code and I get to a point where I just can't figure out what exactly to do.
The tree isn't recursive, so I can follow everything really until I start trying to modify it so it uses lazy deletion instead of real deletion. (Right now it nulls out the node it deletes)
What I have managed to figure out:
I added a flag to the node class to set them as deleted
I've implemented a search method that works, it even seems to register if my nodes are deleted or not(lazily)
I know that the rest of the tree class should treat the nodes that are flagged as deleted such that they are not there.
What I don't know:
I've looked at MANY resources and some say all you need to do is set
the node's deleted flag to true. Does this mean that I don't have to
worry about the linking after their flag is set?
Is an appropriate way to do this very superficial? As in, just don't let the methods report that something is found if the flag is set to deleted even though the methods do find something?
In what method(s) should I change to use lazy deletion? Only the delete() method?
If I only change the delete method, how is this picked up by the other methods?
Does the search method look okay?
Here's the rest of the code so you can see what I'm using. I'm really frustrated because I honestly understand how to delete nodes completely way better then this stupid lazy deletion implementation. It's what they teach in the book! lol
Please help... :(
Search Method
So here's my search method:
public String search(E data){
Node<E> current = root;
String result = "";
while(current != null){
if(data.compareTo(current.e) < 0){
current = current.left;
}
else if (data.compareTo(current.e) > 0){
current = current.right;
}
else{
if (current.isDeleted == false){
return result += "Found node with matching data that is not deleted!";
}
else{
return result += "Found deleted data, not usable, continuing search\n";
}
}
}
return result += "Did not find non-deleted matching node!";
}
Tree Class
Tree Code (The real deletion method is commented out at the end so I could replace it with the lazy deletion):
package mybinarytreeexample;
public class MyBinaryTree> {
private Node<E> root = null;
public class Node<E> {
public boolean isDeleted = false;
public E e = null;
public Node<E> left = null;
public Node<E> right = null;
}
public boolean insert(E e) {
// if empty tree, insert a new node as the root node
// and assign the elementy to it
if (root == null) {
root = new Node();
root.e = e;
return true;
}
// otherwise, binary search until a null child pointer
// is found
Node<E> parent = null;
Node<E> child = root;
while (child != null) {
if (e.compareTo(child.e) < 0) {
parent = child;
child = child.left;
} else if (e.compareTo(child.e) > 0) {
parent = child;
child = child.right;
} else {
if(child.isDeleted){
child.isDeleted = false;
return true;
}
return false;
}
}
// if e < parent.e create a new node, link it to
// the binary tree and assign the element to it
if (e.compareTo(parent.e) < 0) {
parent.left = new Node();
parent.left.e = e;
} else {
parent.right = new Node();
parent.right.e = e;
}
return true;
}
public void inorder() {
System.out.print("inorder: ");
inorder(root);
System.out.println();
}
private void inorder(Node<E> current) {
if (current != null) {
inorder(current.left);
System.out.printf("%3s", current.e);
inorder(current.right);
}
}
public void preorder() {
System.out.print("preorder: ");
preorder(root);
System.out.println();
}
private void preorder(Node<E> current) {
if (current != null) {
System.out.printf("%3s", current.e);
preorder(current.left);
preorder(current.right);
}
}
public void postorder() {
System.out.print("postorder: ");
postorder(root);
System.out.println();
}
private void postorder(Node<E> current) {
if (current != null) {
postorder(current.left);
postorder(current.right);
System.out.printf("%3s", current.e);
}
}
public String search(E data){
Node<E> current = root;
String result = "";
while(current != null){
if(data.compareTo(current.e) < 0){
current = current.left;
}
else if (data.compareTo(current.e) > 0){
current = current.right;
}
else{
if (current.isDeleted == false){
return result += "Found node with matching data that is not deleted!";
}
else{
return result += "Found deleted data, not usable, continuing search\n";
}
}
}
return result += "Did not find non-deleted matching node!";
}
public boolean delete(E e) {
}
// an iterator allows elements to be modified, but can mess with
// the order if element not written with immutable key; it is better
// to use delete to remove and delete/insert to remove or replace a
// node
public java.util.Iterator<E> iterator() {
return new PreorderIterator();
}
private class PreorderIterator implements java.util.Iterator<E> {
private java.util.LinkedList<E> ll = new java.util.LinkedList();
private java.util.Iterator<E> pit= null;
// create a LinkedList object that uses a linked list of nodes that
// contain references to the elements of the nodes of the binary tree
// in preorder
public PreorderIterator() {
buildListInPreorder(root);
pit = ll.iterator();
}
private void buildListInPreorder(Node<E> current) {
if (current != null) {
ll.add(current.e);
buildListInPreorder(current.left);
buildListInPreorder(current.right);
}
}
// check to see if their is another node in the LinkedList
#Override
public boolean hasNext() {
return pit.hasNext();
}
// reference the next node in the LinkedList and return a
// reference to the element in the node of the binary tree
#Override
public E next() {
return pit.next();
}
#Override
public void remove() {
throw new UnsupportedOperationException("NO!");
}
}
}
// binary search until found or not in list
// boolean found = false;
// Node<E> parent = null;
// Node<E> child = root;
//
// while (child != null) {
// if (e.compareTo(child.e) < 0) {
// parent = child;
// child = child.left;
// } else if (e.compareTo(child.e) > 0) {
// parent = child;
// child = child.right;
// } else {
// found = true;
// break;
// }
// }
//
//
// if (found) {
// // if root only is the only node, set root to null
// if (child == root && root.left == null && root.right == null)
// root = null;
// // if leaf, remove
// else if (child.left == null && child.right == null) {
// if (parent.left == child)
// parent.left = null;
// else
// parent.right = null;
// } else
// // if the found node is not a leaf
// // and the found node only has a right child,
// // connect the parent of the found node (the one
// // to be deleted) to the right child of the
// // found node
// if (child.left == null) {
// if (parent.left == child)
// parent.left = child.right;
// else
// parent.right = child.right;
// } else {
// // if the found node has a left child,
// // the node in the left subtree with the largest element
// // (i. e. the right most node in the left subtree)
// // takes the place of the node to be deleted
// Node<E> parentLargest = child;
// Node<E> largest = child.left;
// while (largest.right != null) {
// parentLargest = largest;
// largest = largest.right;
// }
//
// // replace the lement in the found node with the element in
// // the right most node of the left subtree
// child.e = largest.e;
//
// // if the parent of the node of the largest element in the
// // left subtree is the found node, set the left pointer of the
// // found node to point to left child of its left child
// if (parentLargest == child)
// child.left = largest.left;
// else
// // otherwise, set the right child pointer of the parent of
// // largest element in the left subtreeto point to the left
// // subtree of the node of the largest element in the left
// // subtree
// parentLargest.right = largest.left;
// }
//
// } // end if found
//
// return found;
What changes is that your tree only grows in term of real space used, and never shrinks. This can be very useful if you choose a list as a data-structure to implement your tree, rather than the usual construct Node E {V value; E right; E; left}. I will come back on this later.
I've looked at MANY resources and some say all you need to do is set
the node's deleted flag to true. Does this mean that I don't have to
worry about the linking after their flag is set?
Yes, if by linking you mean node.left, node.right. Delete simply mark as deleted and that's it. It change nothing else, and it should not, because x.CompareTo(y) must be still working even if x or y are marked as deleted
Is an appropriate way to do this very superficial? As in, just don't
let the methods report that something is found if the flag is set to
deleted even though the methods do find something?
Well by definition of this method "something" means a node without the deleted flag. Anything with the deleted flag is "nothing" for the user of the tree.
what method(s) should I change to use lazy deletion? Only the delete()
method?
Of course not. You already changed the search method yourself. Let's take the isEmpty(). You should keep a counter of deleted nodes and one of total nodes. If they are equal the tree is empty. Otherwise the tree is not.
There is a small bug in your algorithm. When you insert and find out that you land on a deleted node, you just unmark that node. You must also set the value of the node. After all compareTo doesnt insure all fields are strictly equal, just that the objects are equivalent.
if(child.isDeleted){
child.isDeleted = false;
child.e = e; <---- missing
return true;
}
There might be others.
Side Note:
As said before one instance where this method is useful is a tree backed by an list (let's say array list). With this method the children of element at position i are at position 2*i+1 and 2*i+2. Usually when you delete a node p with children, you replace that node with the leftmost node q of the right subtree (or rightmost node in the left subtree). Here you can just mark p as deleted and swap the value of the deleted node and leftmost. Your array stays intact in memory
I am struggling to figure out how to code a recursive algorithm to count the number of leaves in a Binary Tree (not a complete tree). I get as far as traversing to the far most left leaf and don't know what to return from there. I am trying to get the count by loading the leaves into a list and getting the size of that list. This is probably a bad way to go about the count.
public int countLeaves ( ) {
List< Node<E> > leafList = new ArrayList< Node<E> >();
//BinaryTree<Node<E>> treeList = new BinaryTree(root);
if(root.left != null)
{
root = root.left;
countLeaves();
}
if(root.right != null)
{
root = root.right;
countLeaves();
}
if(root.left == null && root.right == null)
{
leafList.add(root);
}
return();
}
Elaborating on #dasblinkenlight idea. You want to recursively call a countleaves on root node & pass back the # to caller. Something on the following lines.
public int countLeaves() {
return countLeaves(root);
}
/**
* Recursively count all nodes
*/
private static int countLeaves (Node<E> node) {
if(node==null)
return 0;
if(node.left ==null && node.right == null)
return 1;
else {
return countLeaves(node.left) + countLeaves(node.right);
}
}
Edit: It appears, a similar problem was previously asked counting number of leaf nodes in binary tree
The problem with your implementation is that it does not restore the value of member variable root back to the state that it had prior to entering the method. You could do it by storing the value in a local variable, i.e.
Node<E> oldRoot = root;
... // your method goes here
root = oldRoot;
However, a better approach is to take Node<E> as an argument, rather than relying on a shared variable:
public int countLeaves() {
return countLeaves(root);
}
private static int countLeaves (Node<E> node) {
... // Do counting here
}
I have a link list, and I want to be able to look two nodes ahead. I need to check if the first two nodes have integers, and if they do, and the third node says ADD, then I need to condense that information into one node and free the other two nodes.
I'm confused about what should go in my while loop. I check if the third node points to null, but somehow that's not giving me the right output. I don't know if I'm handling my node.next correctly either. Some of this is pseudocode now.
while(node1.next.next.next != NULL){
if((node1.data.isInteger() && (node2.data.isInteger()){
if(node3.data.equals('add')){
node1.data = node1.data + node2.data;
} else {
//ERROR
}
garbage_ptr1 = node2;
garbage_ptr2 = node3;
node1.next = node3.next;
free(garbage_ptr1);
free(garbage_ptr2);
node2.next = node1.next.next;
node3.next = node2.next.next;
} else {
node1.next = node1.next.next;
node2.next = node1.next.next;
node3.next = node2.next.next;
}
An approach that I find easier is to maintain a small array that acts as a window onto the list, and to look for matches on the array. The code also becomes a lot cleaner and simpler if you move your null checks into utility methods. By doing these things, the loop over the list only needs to check the last element of the window to terminate.
A sketch of this in Java:
/* small utility methods to avoid null checks everywhere */
public static Node getNext(Node n) { return n != null ? n.next : null; }
public static boolean isInteger(Node n) {
return (n != null) && (n.data != null) && (n.data instanceof Integer);
}
public static boolean isAdd(Node n) {
return (n != null) && (n.data != null) && n.data.equals("add");
}
/* checks for a match in the 3-node window */
public boolean isMatch(Node[] w) {
return isInteger(w[0]) && isInteger(w[1]) && isAdd(w[2]);
}
/* Loads the 3-node window with 'n' and the next two nodes on the list */
public void loadWindow(Node[] w, Node n) {
w[0] = n; w[1] = getNext(w[0]); w[2] = getNext(w[1]);
}
/* shifts the window down by one node */
public void shiftWindow(Node[] w) { loadWindow(w, w[1]); }
...
Node[] window = new Node[3];
loadWindow( window, node1 );
while (window[2] != null) {
if (isMatch(window)) {
window[0].data = stack[0].data + stack[1].data;
window[0].next = window[2].next;
loadWindow(window, window[0]); // reload the stack after eliminating two nodes
} else {
shiftWindow( window );
}
}