I have the code for printing a the contents of a binary search tree in-order (ascending) using recursion. I understand that the helper method calls on the recursive method with root as the beginning node value. But I don't understand how the recursive code works conceptually. Could anyone explain?
//ascend method that prints values in the tree in ascending order
//recursive method below
public void printAscending() {
printAscending(root);
}
private void printAscending(Node node) {
if(node != null) {
printAscending(node.left);
System.out.println(node.data);
printAscending(node.right);
}
}
Consider the following (trivial) tree:
1
You'd be calling the function on the one (the root) and it is obvious to see that the result is 1.
Now consider the following (slightly larger) tree:
2
1
The root is now 2 and the output (manually traced by hand) gives 1 2. (spaces added for clarity)
Similar manual tracing on the following gives us 1 2 3:
2
1 3
So we can now see that for small testcases, it seems to work fine.
Let's try proving it for larger testcases.
For any null node (i.e. if we are at a non-existant tree/subtree) we just exit.
For any non-null node, the printAscending(node.left) line is called first. This line MUST finish execution before anything else runs. This calls the printAscending() function using node.left as parameter which is equivalent to just looking at the left subtree of the current node, finishing the work there and then continuing the code. We can keep going down the left until we reach a null node. At this point of time, it moves back upwards, resuming from where it had stopped off. It runs System.out.println(node.data) which gives the output of a single node and then runs printAscending(node.right). This causes it to enter the right subtree of the current node. Note that in this subtree, it runs the complete code (i.e. runs the left, center and then right parts). Once it is done running through the right subtree, it backs out of the subtree and the current node. This makes the node just above it (the parent) move on to the next part of the code.
If you follow a similar working, you'll see that the whole left subtree of the root is processed first, then the root is printed and then whole right subtree is processed.
// public entry point, reuses the recursive function
public void printAscending() {
printAscending(root);
}
// print this node and all of its descendants
private void printAscending(Node node) {
// is there actually a node here
// or was this called from a node with no children
if(node != null) {
// print everything that's earlier than this node
printAscending(node.left);
// print this node's value
System.out.println(node.data);
// print everything that's afterthan this node
printAscending(node.right);
}
}
public void printInOrder() {
if (left != null) {
left.printInOrder();
}
System.out.println(data);
if (right != null) {
right.printInOrder();
}
}
Related
The answer needs to be iterative, not recursive and the trees don't have to have the same structure, only the same numbers. I think I need to use a vertex traversal, but I am not sure how to implement that without using recursion.
This is what I had, but it doesn't pass the given tests. Also, I can't use any helper functions.
Node leftTree = t1;
Node rightTree = t2;
if(t1 == null && t2 == null)
return true;
else if (t1 != null && t2 == null)
return false;
else if (t1 == null && t2 != null)
return false;
else
{
if(leftTree.key == rightTree.key && problem1(leftTree.left, rightTree.left) == true
&& problem1(leftTree.right, rightTree.right) == true)
return true;
}
return false;
The recursion, where you compare left with left and right with right, will not work, because you can have the same keys but in a different topology. You need to visit the nodes in-order in the two trees in parallel.
One way of going through a tree without using recursion or extra memory is via a Morris traversal, where you temporarily put a tree in the rightmost position of its left subtree, and "return" from the recursion by following the right pointer there.
Here is an implementation in C, because I have one lying around. In Java it won't be that different. The rightmost_to() function returns the rightmost node in the left child of the current node, or the current node itself. You use it put the current node in the right child there, so when you get down to that point, going right emulates returning from the recursion.
void morris(stree *t)
{
struct node *curr = *t;
while (curr) {
if (!curr->left) {
printf("%d\n", curr->value);
curr = curr->right;
} else {
stree pred = *rightmost_to(&curr->left, curr);
assert(pred->right == 0 || pred->right == curr);
if (pred->right == 0) {
pred->right = curr;
curr = curr->left;
} else {
printf("%d\n", curr->value);
pred->right = 0;
curr = curr->right;
}
}
}
}
You will visit each node in order, without recursion, and without using extra memory. Whenever you recurse, you put the node you are in at the rightmost position, so you automatically come back to it. You can recognise that you are seeing the node for the second time because you find it when searching for the rightmost. Then you restore the tree instead of going left once more.
If you need to compare two trees, have two current nodes, and you should be fine. It does use an extra function, rightmost_to(), but it is a simple loop that you can easily embed without any issues. It is a line or two if you do that.
If you are allowed to put a parent pointer in the nodes, I think you can also traverse the trees without using extra memory doing something like this:
#define left_child(t) \
((t)->parent && (t)->parent->left == (t))
void parent_traverse(stree t)
{
enum { DOWN, UP } state = DOWN;
while (t) {
switch (state) {
case DOWN:
// Recurse as far left as we can...
while (t->left) { t = t->left; }
// Emit the leaf we find there
printf("(,%d,", t->value); // VISIT
// Then go right, if we can, or up if we can't.
if (t->right) { t = t->right; }
else { state = UP; }
break;
case UP:
if (!t->parent) return; // we have returned to the root...
if (left_child(t)) {
// Returning from a left child, we emit the parent
t = t->parent;
printf(",%d,", t->value); // VISIT
// Then we go right if we can't, or continue up
// (t is already the parent) if we cannot.
if (t->right) { t = t->right; state = DOWN; }
} else {
// Returning from a right child just means going up
t = t->parent;
}
break;
}
}
}
Sorry, it is C again, but just look at how t is updated to its left, right or parent node as we run through the tree. I cut that out of some code I have, and I might have copied it wrong, but you should get the idea. You can keep track of which direction you are moving, and essentially move along the "edge" of the tree, down left edges, under them and up, then down to the right, turn, and move up, and so on. If you have the state for both trees, you should be able to do that traversal in parallel in the two. Everwhere the code "visits" a node, you will compare the two nodes.
I don't know how useful this is, but it is at least a couple of ways that you can compare two trees with only constant extra memory usage and no recursion.
Of course, if it is a simple assignment and the time complexity doesn't matter, run through one tree and look up in the other in O(n log n) (balanced) or O(n^2). :)
I am currently building a ScapeGoatTree for a project. However I am having an issue getting my rebuild function to properly take hold of the scapegoat node it is building. In the below code you will see inside the 'if( height >alpha height)' statement 2 more if statements. The first if statement compares my scapegoat node (which I know with current test data should be the static root.left node) and it correctly says they are equal. However when I try to change the Placeholder node(Which should hopefully be an object reference to root.left) it merely overwrites my placeholder node. So thus the second if statement does not fire off, but I need the returned value of my FindScapeGoat to be the node being edited.
I am not going to lie I have always been a bit bad at understanding the pass by reference and pass by value differences in languages, but I really do need to figure out how I can properly apply changes to root.left without needing a specific call to it (since the function will not always choose root.left as the scapegoat node I need a way to call various nodes in my tree rooted at a static location).
public static void Insert(int key) {
height = dupflag = 0;
root = insertHelp(root, key);
if(dupflag == 0) MaxNodeCount++; //If inserted value wasn't duplicate increase max node count
double alphaHeight = ((Math.log(MaxNodeCount) / Math.log(1 / alpha)) + 1);
if (height > alphaHeight){
Node ToBeRebalanced = FindScapegoat(root, key); // Find scapegoat node
int sizeRoot = TreeSize(ToBeRebalanced, 0);
if(ToBeRebalanced == root.left) System.out.println("Scapegoat node == root.left");
ToBeRebalanced = RebuildTree(sizeRoot+1, ToBeRebalanced);
if(ToBeRebalanced == root.left) System.out.println("Scapegoat node == root.left");
Print(ToBeRebalanced);
Print(root);
}
}
To address the value/reference issue: non-primitive variables in Java behave (mostly, big caveat that's way out of scope for this answer) like pointers to memory locations. When you say ToBeReplaced you're changing the memory address that ToBeReplaced points to.
To your more specific issue, there are a couple of ways to handle this. The way that I would handle it would be to change the return from FindScapegoat to indicate whether the node is left or right. It seems like it's examining only the immediate children, so there's no need to return a reference to the node itself.
Something like this:
public enum Side {
LEFT,
RIGHT
}
//...
Side ToBeRebalanced = FindScapegoat(root, key); // Find scapegoat node
if (ToBeRebalanced == Side.Left){
int sizeRoot = TreeSize(root.left, 0);
root.left = RebuildTree(sizeRoot+1, root.left);
} else {
int sizeRoot = TreeSize(root.right, 0);
root.right = RebuildTree(sizeRoot+1, root.right);
}
You then could move the TreeSize call into the RebuildTree method to avoid the duplicated code.
I'm trying to find a value in a binary tree and returning the node that has the value I'm looking for.
I did an algorithm that works well when the value is not in a very deep level of the tree, but when the value is in a deep position I get a java.lang.StackOverflowError. Here is my code:
class Nope {
Nope left, right;
int value;
public Nope find(int v){
if(v > this.value && this.right != null)
return right.find(v);
if(v < this.value && this.left != null)
return left.find(v);
if(this.value == v)
return this;
return null;
}
}
Can any one suggest me a solution about this issue (I heard about something like tail optimization recursion) but I'm not sure of it working in Java.
The simplest approach is to convert this into a while loop, which just maintains state of "the current node we're testing".
On each iteration of the loop, there are three possibilities:
The current node has the right value, in which case you can return it
The current node has a subnode on the correct "side", in which case you can continue iterating with that subnode as the new "current node"
Neither of the above is the case, in which case the value isn't found and you can return null
So something like:
public Nope find(int v) {
Nope current = this;
while (current != null) {
if (current.value == v) {
return current;
}
// This will drop out of the loop naturally if there's no appropriate subnode
current = v < current.value ? current.left : current.right;
}
return null;
}
Or with even less code, but perhaps less readably:
public Nope find(int v) {
Nope current = this;
// Keep navigating down the tree until either we've run
// out of nodes to look at, or we've found the right value.
while (current != null && current.value != v) {
current = v < current.value ? current.left : current.right;
}
return current;
}
An example of your code recast as iteration:
class Nope {
// keep these fields
Nope left, right;
int value;
public Nope find(int v){
Nope n = this;
while (n != null)
{
if (v > n.value)
n = n.right;
else if (v < n.value)
n = n.left;
else // v == n.value
return n;
}
return null;
}
}
Edit: just a note on how this works, in case it's unclear. Since you never need to remember anything about how you got to the current node, we only keep track of the root of the current subtree we need to search. At each step, we've either determined there is no subtree left to search (first condition), there might be a subtree to the left or right (middle two conditions), or that we have actually found the value at the root of the current subtree (last condition). We keep looking until we run out of subtrees (while condition) and, if we do run out, we know the value isn't in the tree and we return null.
Edit: As pointed out in the comments, the use of consecutive ifs is a problem. I have updated the code to use if/else if/else.
Tree searches are used to avoid iterating over large arrays.
The weakness of the tree approach is when the node values are ordered. As the tree is loaded, every node goes to the left or right, causing a lot of recursion. Having said that, stack overflow takes a lot of recursion.
You can either hash the values, which will tend to balance the tree, or you can enhance your tree building algorithm to balance the tree if a particular branch gets too long.
Having said that, you should also look at how many nodes are in your tree that there are enough to cause a stack overflow. You may have a bug in your code that is not shown here.
You can use Xss JVM argument to increase the memory allocated to the thread stack. This will allow you to have a larger method call stack.
-Xsssize
Sets the thread stack size (in bytes). Append the letter k or K to indicate KB, m or M to indicate MB, g or G to indicate GB. The
default value depends on virtual memory.
The following examples set the thread stack size to 1024 KB in
different units:
-Xss1m
-Xss1024k
-Xss1048576
Ref: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html
Otherwise you can always convert the recursion to the a loop, that would mean you would have to manage the call stack of the method (arguments and return values) yourself in a stack, that can become messy.
Note: For search operation there's no need for a stack as mentioned by Jon Skeet. Search doesn't need to keep track of where it's been. However for backtracking a reference to parent would be required, and we will have to make sure that we always start with left child.
I know this is pretty straight forward code but wondering how exactly the internal working is.
public static int getHeight(TreeNode root) {
if (root == null) {
return 0;
}
System.out.print(getHeight(root.left) +"\t");
return Math.max(getHeight(root.left), getHeight(root.right)) + 1;
}
For my understanding, I added print statement but it results the following.
printing root.left() prints this: 0 0 0 1 0 0 0
printing root.right() prints this: 0 0 2 0 0 3 0 0 2 0 0 0 1 0
Following is the Tree created in the main program:
TreeNode parent = new TreeNode(10);
parent.insertInOrder(2);
parent.insertInOrder(13);
parent.insertInOrder(5);
parent.insertInOrder(6);
parent.insertInOrder(15);
parent.insertInOrder(6);
How is this printing the above result and how is it working. If anyone can explain me with the above example, it would really help me.
I know how traversals work and how to print the tree but I really want to understand the above output. If anyone can help then it would be great.
void setLeftChild(TreeNode left)
{
this.left = left;
if(left == null)
{
left.parent = this;
}
}
void setRightChild(TreeNode right)
{
this.right = right;
if(right == null)
{
right.parent = this;
}
}
void insertInOrder(int d)
{
if(d <= data)
{
if(left == null)
{
setLeftChild(new TreeNode(d));
}
else
{
left.insertInOrder(d);
}
}
else{
if(right == null)
{
setRightChild(new TreeNode(d));
}
else{
right.insertInOrder(d);
}
}
size++;
}
You should create a function that outputs information about the tree. For example, this function does a preorder traversal, showing information about each node:
public static void ShowTree(TreeNode root, TreeNode parent, depth)
{
if (root == null) return;
// output 'depth' spaces.
// The indentation will help show the structure of the tree.
// output node value, and parent (if parent not null)
// Traverse the left node
ShowTree(root.left, root, depth+1);
// Traverse the right node
ShowTree(root.right, root, depth+1);
}
Call that function with ShowTree(tree, null, 0). The resulting output will show the structure of the tree, and you can determine if the tree is balanced. It's a useful thing to have when you're developing tree code because you can do an insert, for example, then call ShowTree to see if the insert worked as expected.
Update
The code's output is a little strange because your print statement results in a recursive call. So every node below the current node ends up getting printed multiple times.
I think you want to do this:
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
// now output output leftHeight or rightHeight, or both
return Math.max(leftHeight, rightHeight) + 1;
That way you won't get the multiple recursive calls that produce the strange output.
More info
The reason you're seeing those extra recursive calls is because you're calling getHeight(root.left) twice. Let's say your tree looks like this:
root
/
child
/
grandchild
So you call getHeight(root). Then:
getHeight(child) is called in your print statement
getHeight(grandchild) is called in your print statement
getHeight(null) is called in your print statement
getHeight(grandchild) prints 0
getHeight(null) is called twice (once for the left node and once for the right node) in the return statement
getHeight(grandchild) returns 1
getHeight(child) prints 1
getHeight(grandchild) is called in the return statement
getHeight(null) is called in your print statement
getHeight(grandchild) prints 0
getHeight(grandchild) returns 1
getHeight(null) (the right node) is called in the return statement
...
You see where the problem is? getHeight(grandchild) is called again! Every time your print statement calls getHeight, it has to walk every descendant node. So the height of every node is output multiple times. The deeper the node is in the tree, the more often it will be output.
The change I suggested in my update above prevents that by ensuring that no node is visited more than once.
I'm looking into depth first search and the examples I found are looking for a particular answer, lets say the number 10.
It goes through the tree discarding every node that isn't 10 and stop when it finds 10.
Is it possible to use depth first search or another algorithm to search every branch of the tree? I would like it to run a scenario and come up with a value and store that into a variable possibly named highestValue.
It would then search the next branch and get a value and store that into a variable possibly named Value. Then it would compare highestValue to Value and if (Value > highestValue) highestValue = Value.
It would repeat the process until it is finished running every possible scenario. Any ideas? I should mention I'm writing this in Java.
DFS is easiest if we want to visit every node in the graph. However, if we have a very large tree and want to be prepared to quit when we get too far from the original node, DFS can search thousands of ancestors of the node but never search all of the nodes children.
Strictly speaking, it depends on how the data in your graph is organize. Source
Since you're still wondering how it might work, this piece of code might help you figure that out. This works for graphs, take a look. It DFSes every node, but stops when it reaches the node we want to find.
To get the highest value, just store the max value into an int variable, and continue searching and comparing each node's data to the current max inside the int variable.
public static boolean search(Graph g, Node start, Node end) {
LinkedList<Node> stack = new LinkedList<Node>();
for (Node u : g.getNodes()) {
u.state = State.Unvisited;
}
start.state = State.Visiting;
stack.add(start);
Node u;
while (!stack.isEmpty()) {
u = stack.removeFirst();
if (u != null) {
for ( Node v : u.getAdjacent() ) {
if (v.state == State.Unvisited) {
if (v == end) {
return true;
}
else {
v.state = State.Visiting;
stack.add(v);
}
}
}
u.state = State.Visited;
}
}
return false;
}