java version "1.8.0_92"
I am studying trees and how to traverse them using recursion. But I am confused about it works.
public void preOrder(BinaryTree root) {
if(root != null) {
System.out.println(root);
preOrder(root.leftChild); <-- this gets called and will start from the top of the function
preOrder(root.rightChild); <-- how can this get called if the top one will always calls itself?
}
}
I think that the second preOrder will never get called as the call above will always call itself so the second one will never be executed.
It does not always call itself. It keeps going until it bottoms out with a null leftChild. Then execution returns without doing anything -- it backs up one level and recurs on the rightChild of the lowest-level parent node. When that call also runs out of children, the execution returns from handling this lowest-level parent node, again backing up one call, and does the rightChild of that node ... until the entire tree has been traversed.
Think of it has as opening up a whole bunch of doors until you find what you're looking for, then you have to go back and close/check the other ones.
public void preOrder(BinaryTree root) {
if(root != null) {
System.out.println(root);
preOrder(root.leftChild); <-- this gets called and will start from the top of the function
preOrder(root.rightChild); <-- how can this get called if the top one will always calls itself?
}
}
We can replace the preOrder calls with the matching code to look like:
public void preOrder(BinaryTree root) {
if(root != null) { <-- note the if check
System.out.println(root);
if(root.leftChild!= null) { <-- note the if check
System.out.println(root.leftChild.leftChild);
preOrder(root.leftChild.leftChild); <- this expands into another if block
preOrder(root.leftChild.rightChild); <- this also expands
}
if(root.rightChild!= null) { <-- note the if check
System.out.println(root.rightChild.leftChild);
preOrder(root.rightChild.leftChild);
preOrder(root.rightChild.rightChild);
}
}
}
It keeps expanding outwards... until you hit the special "base" if conditional that stops the recursion. In this case it is when you've found a leaf node of the tree, i.e. node == null, it stops the expansion because the if conditional is no longer true and everything begins to collapse in on itself, or in other words it can continue executing normally down the block of code.
Recursion may seem to be confused when you just start to learn. Firstly, you can think of a subproblem. For preOder, it always prints out the root node, and left node, then right node. All you need is to solve a subproblem. (a basic simple tree below)
root
/ \
left right
/ \
... ...
Now go back to look at the code:
if(root != null) {
System.out.println(root);
preOrder(root.leftChild); // the left node now becomes another root, and keep making the next left node root until the next left node is null.
preOrder(root.rightChild); // this line of code won't be executed until the last preOrder function call its root == null(hit the condition.)
}
Trust recursion; it will always do the rest of part for you if your condition is correct. I agree to run debug mode to have a better understanding. It is very useful to learn how to use "step in" when you try to understand how code works.
Once root.leftChild becomes null (ie, when you get to a leaf of the tree), preOrder will be called like so: preOrder(null). When this happens, the condition will evaluate to false, and recursion unwind and stop, at which point preOrder(root.rightChild) will be evaluated.
Here's a call trace (in Scala):
case class BinaryTree(nodeName: String, leftChild: Option[BinaryTree], rightChild: Option[BinaryTree]) {
def preOrder(root: Option[BinaryTree], depth: Int = 0) {
root match {
case Some(root) => {
println(" " * depth + root.nodeName)
preOrder(root.leftChild, depth+4)
preOrder(root.rightChild, depth+4)
}
case None => println(" " * depth + "leaf")
}
}
}
val tree = new BinaryTree(
"root",
Some(new BinaryTree(
"a",
Some(new BinaryTree("aa", None, None)),
Some(new BinaryTree("ab", None, None)))),
Some(new BinaryTree(
"b",
Some(new BinaryTree("ba", None, None)),
Some(new BinaryTree("bb", None, None)))))
tree.preOrder(Some(tree))
root
a
aa
leaf
leaf
ab
leaf
leaf
b
ba
leaf
leaf
bb
leaf
leaf
Related
I have been scratching my head to find a solution to this problem. I am not very good with data structures and it seems that my brain melts a little whenever I have to do anything to do with trees.
Suppose we have a Node():
Node(name: String, children: List<Node>?)
And we have a tree made up of these nodes:
var node6 = Node("6", null)
var node5 = Node("5", null)
var node4 = Node("4", null)
var node3 = Node("3", listOf(node5, node6))
var node2 = Node("2", null)
var node1 = Node("1", listOf(node2, node3, node4))
What approach could I take to find the path (stored) to node6 while only having the root available?
Thank you kindly for any advice you could offer!
Solution as per JayC667's guidance:
fun recursiveCheck(
nodeA: Node,
nodePath: Stack<Node>,
nodeToFind: String
) : Boolean {
// Push param node to stack
nodePath.push(nodeA)
// Check param node
if(nodeA.name == nodeToFind) {
return true
}
if(nodeA.children != null) {
// Iterate over all children using recursive check
for(child in nodeA.children!!) {
// child found as param node
if(recursiveCheck(child, nodePath, nodeToFind)) return true
}
}
// Did not find node, popping off stack
nodePath.pop()
return false
}
Simple. If the node only exists once in the tree and is reachable from the root, of course.
Use a Stack as node path stack:
Starting method: create stack, call recursive check method, params: (root node, node path stack, node to find)
Recursive Check method: push param node to stack, check param node, iterate over all children + for each child call recursive check method. If child was found as param node or in the subcalls, immediately return true (and return)
each time you leave the recursive check method (at the end, if you have NOT found the node), pop the current element off the stack.
if in the starting method the Recursive Check method has returned true, your node path will lie on the stack
I have this recursive function that is supposed to delete the node that comes after the specified one in
a doubly linked list. However My method Isn't deleting anything. I am having trouble with rearranging the values in the list. Any ideas?
private void deleteAfterThis(T data, Node headAux) {
if(headAux == null) {
return;
}
Node deleteAfter = new Node(data);
Node target = deleteAfter.next;
if(target == null) {
return;
}
if(deleteAfter.prev == null){
if(target != tail && target==headAux) {
deleteAfter.next = target.next;
target.next.prev = deleteAfter;
size--;
deleteAfterThis(data, headAux.next);
}
else if(target == tail && target == headAux) {
deleteAfter.next = null;
deleteAfter = tail;
size--;
return;
}
}
else if(deleteAfter.prev != null) {
if(target != tail && target == headAux) {
deleteAfter.next = target.next;
target.next.prev = deleteAfter;
size--;
deleteAfterThis(data, headAux.next);
}
else if( target == tail && target == headAux) {
deleteAfter.next = null;
deleteAfter = tail;
size--;
return;
}
}
deleteAfterThis(data, headAux.next);
}
One mistake I see right off the bat is that you should not be creating a completely new node for deleteAfter. Intuitively, does it make sense to have to create a new node when attempting to delete one? I'll assume that, even knowing what the constructor for Node actually looks like, it sets the next and prev pointers to nodes to null. As a result, you'll keep recursively updating headAux until it's null without ever deleting anything. It seems what you want deleteAfter to be is headAux.next.
Another bug I see is that you've copy and pasted your checking logic twice - I recommend stepping through both cases and verifying if the logic should be identical within each block of the if and else-if blocks (it probably shouldn't).
Stepping into the logic, you should realize that the prev node of the current (headAux in your code) would be null only if headAux is the head of the list. Thus, it would be a bit more clear to rewrite the headAux.prev check as verifying if headAux is equal to the head of the linked list.
Looking at the actual deletion logic, it seems to make sense in the general case to me (assuming the fact that deleteAfter is the next node of headAux as stated above). You're making the prev of the node to be deleted to point to the deleted node's prev node and the next of the previous node (after having set the pointer, which I'm not too big of a fan of but it works) point to deleteAfter.
Lastly, when you do actually locate the node you'd like to delete, you probably shouldn't be calling the recursive function again. You already handle the setting of pointers correctly, so there shouldn't be a need to do so.
I would highly recommend you (re-)draw a sample use-case of your circular linked list and perform deletion on a sheet of paper before jumping to coding the edgecases (which aren't all handled here). The edge cases you should probably be aware of are the following: empty list, deleting head, deleting tail, single-node list. In your code, it seems that you did try to handle the deletion of the head (you'd have to remember to set the head afterwards). After getting that to work, making deletion work on other cases should be a breeze.
I am just starting out with java and recursive methods and i need some help:
I need to determine if two Binary Search Trees has exactly the same set of elements, regardless of the structure of the tree.
I have written a method that checks if the the tree contains an element and its called contains()
this is what i got so far:
public boolean sameContents(Node n2) {
if (contains(n2, n2.key) && n2.left == null && n2.right == null) { return true; }
if (contains(n2, n2.key) && n2.left != null) { sameContents(n2.left); }
if (contains(n2, n2.key) && n2.right != null) { sameContents(n2.right); }
return false;
}
Basicly my idea is that the method is running as long as a node still has a child, and if the trees match.
I call the method with for example testTree1.sameContents(testTree2); but the method always returns false...
Can someone point out how this should be done?
The best way to do this is with an Iterator object - if two binary search trees contain the same elements then their iterators' next methods should return the same values (even if their structures are different).
// returns true if the trees are equivalent, else false
Iterator itr1 = tree1.getIterator();
Iterator itr2 = tree2.getIterator();
while(itr1.hasNext() && itr2.hasNext()) {
if(!itr1.next().equals(itr2.next())) {
return false;
}
}
return !itr1.hasNext() && !itr2.hasNext(); // returns true if trees were the same size, else false
You ought to already have an inorder binary tree traversal method, so you've already got an Iterator - just add an ArrayList/Stack to take the place of the call stack so that you can pause the traversal (whenever you would be making a recursive method call, store the current node to your Stack)
There is another way to do that. You can convert your trees into string representations, using pre-order traversal or in-order traversal. It will take O(n) time. Than you can check whether these strings equal or not. It can be done in O(n) time too. So, the total running time is O(n).
This method looks similar to the solution with iterators but this one is more generic, since can be used for 'is-subtree' task (chechs wether tree t1 is subtree of t2). In this case use can use isSubstring() method instead of equals(). If tree t1 is subtree of t2 than t1's string representaion is substring of t2's. The isSubstring() can be done in O(log n) time.
Can you do a inorder traversal on both trees and check if the result of both the traversals are same. If same, could we assume that both trees have the same set of elements.
So, I'm making my own implementation of a Binary Search Tree. In doing so, I've come across an unusual issue, and I have no idea why it's occurring.
setNode Method:
// Sets the Node at the specified Index
public void setNode(int index, NodeInterface<E> node)
{
if(index < 0 || index >= degree)
throw new ArrayIndexOutOfBoundsException("Index: " + index + ", Size: " + nodes.size());
nodes.set(index, (Node<E>) node);
}
The variable nodes is an Array List of Nodes, if that is important.
Now this is where things begin to get messy, being where the error is occurring. It's in the addDescendant method within the BinaryNode Class, which extends the Node class.
addDescendant Method:
// Adds the specified Descendant to this Node
public boolean addDescendant(BinaryNode<E> node)
{
// Determine Node Type
if(compareTo(node) > 0) // Make Left Child
{
if(hasLeftChild())
return getLeftChild().addDescendant(node);
else
{
setNode(0, node); // Link Parent to Child
// ^^^ Works Fine ^^^
node.setNode(1, hasRightChild() ? getRightChild() : this); // Link Child to Parent or Sibling
// ^^^ Does not Work ^^^
return true;
}
}
else if(compareTo(node) < 0) // Make Right Child
{
if(hasRightChild()) // Node already has a Right Child
return getRightChild().addDescendant(node);
else // Node does not have a Right Child
{
if(hasLeftChild())
{
getLeftChild().setNode(1, node); // Link Sibling to Sibling
// ^^^ Does not Work ^^^
}
else
{
setNode(0, node); // Link Parent to Child for the time being
// ^^^ Works Fine ^^^
}
node.setNode(1, this); // Link Child to Parent
// ^^^ Does not Work ^^^
return true;
}
}
else // Duplicate Node
return false;
}
The two important things to note here are the uses of the setNode. It works fine when I use the index of 0, but doesn't work when I use the index of 1.
I'm not getting any errors or warnings, and the code seems to run as it should, but the results are not what I'm expecting.
The method doesn't set the Right Node properly, despite it using the same method to set the Left Node, and that works fine.
I hope I've given enough information, I didn't want to bombard everyone with code.
Unrelated Note:
If you're confused by the connection of my tree, that's because it's not your typical Binary Search Tree. However, the actual structure of the tree shouldn't matter.
Not much information. But I will try:
I think you tree is more unary than binary.
If an index of 1 marks the right child of a node
but also marks the parent of a node, the logic seems
somehow broken to me.
Second thing is in the 'Make left child' part of addDescendant:
It can happen that that more than 2 nodes have the 'root' node
connected to their index 1.
At 'Make Right Child' part of addDescendant:
getLeftChild().setNode(1, node);
Changing nodes of child nodes without further checkings
(by not-using its addDescendant method) is not a good idea.
I am working on assignment for school. It manly consists of a method that takes as input a binary tree and returns a double threaded tree. Eg(if left child = null then left child will be connected with preceding inorder parent and if right child = null the it will link to its inorder succesor. Now I have an idea for the implementation...
I iterate recursively trough the original BINARY tree and store into an array the inorder traversal. Now, because my teachers implementation requires that threaded trees be a different class from binary. I must traverse again trough the binary tree and convert each node from binaryNode to threadedNode thus having at the end a "duplicate" of the initial BinaryTree but as Threadedtree type. After I do this I traverse again trough this threadedTree and whenever i see a null left or right child I refer to the inorder arraylist and find the threads.
Now as you might have noticed this is extremely inefficient, i am essentially traversing the tree 3 times. My professor has stated that this could be done recursively with only one traversal, essentially converting to threadedNode and finding the threads all at once. I have tried multiple ways but i can not find one that works. Does anyone have any kind of tip or some way i can implement it? Thanks
This is the method as specified by the instructor
public static <T> ThreadedNode<T> thread(BinaryNode<T> root)
{
//threads a binary tree
}
The instructor is correct. One traversal is sufficient.
Traverse the original binary tree, creating new ThreadedNodes as you walk this tree.
public static <T> ThreadedNode<T> thread(BinaryNode<T> root) {
// We'll be keeping track of the "previous" node as we go, so use
// a recursive helper method. At first, there is no previous.
return threadHelper(root, null);
}
private static <T> ThreadedNode<T> threadHelper(BinaryNode<T> n, ThreadedNode<T> previous) {
// Create a new threaded node from the current root. Note that the threaded nodes
// are actually created in "preorder". Assume the ThreadedNode constructor sets
// the left, right, threadLeft, and threadRight fields to null.
ThreadedNode<T> t = new ThreadedNode<T>(n.getData());
// First go down the left side, if necessary.
if (n.getLeft() != null) {
// If there is a left child we have to descend. Note that as we go down the
// left side the previous doesn't change, until we start "backing up".
t.left = threadHelper(n.getLeft(), previous);
previous = t.left;
} else {
// If there is no left child, connect our left thread to the previous.
t.threadLeft = previous;
}
// Now before we go down the right side, see if the previous
// node (it will be in the left subtree) needs to point here.
if (previous != null && previous.right == null) {
previous.threadRight = t;
}
if (n.getRight() != null) {
// If there is a right child we can descend the right. As we go down we
// update previous to the current node. We do this just by passing the current
// node as the second parameter.
t.right = threadHelper(n.getRight(), t);
} else {
// No right child, no worries. We'll hook up our thread-right pointer
// later.
}
return t;
}
Consider the tree (A (B (D) ()) C). The first node you hit in an inorder traversal is D. There is no previous node. So save D as previous. Then the next node you hit is B. The previous node was D, which had no right child, so add a threaded right pointer from D to B. Then set previous to B and continue. Next you hit A. B had no right child, so add a threaded right link from B to A. A has a right child so continue, setting previous to A. The next node is C. C has no left child, so add a threaded left link from C to the current value of previous, which is A.
You could skip the second trip of traversal that you mention in your method. You could convert the nodes from BinaryNode to ThreadedNode on the fly. You'd still need to traverse twice, I think, for the inorder traversal, and for finding the threads and converting it to aThreadedTree.
For conversion on the fly, you could use the method that your instructor has given.
HTH!