I am having trouble understanding how this Binary Search Tree method is counting nodes, I have looked at many examples online, however I cannot find one which will explain exactly what is happening.
Here is an example:
public int nodes() {
int leftNodes = 0;
if (left != null) {
leftNodes = left.nodes();
}
int rightNodes = 0;
if (right != null) {
rightNodes = right.nodes();
}
return leftNodes + rightNodes + 1;
}
This is how I am understanding the process of this method, and maybe someone can help me understand where I'm going wrong.
The method is called from outside of itself from a BTS Object; "tree.nodes() etc".
int leftNodes is declared and set to 0.
If there is a left node (assume there is), then the value of leftNodes will be assigned to the return value of the call to nodes();
The recursive call will go through the nodes method again, assigning leftNodes to zero again.
So what I don't understand is where is the leftNodes variable being incremented? It seems like it's just recursing through the method again but the value doesn't change, and from how I see leftNodes and rightNodes will always be 0.
I found another example of BTS counting, this one using C++
int CountNodes(node*root)
{
if(root==NULL)
return 0;
if(root->left!=NULL)
{
n=n+1;
n=CountNodes(root->left);
}
if(root->right!=NULL)
{
n=n+1;
n=CountNodes(root->right);
}
return n;
}
I find this method much easier to follow, as n is clearly being incremented everytime a node is found.
My question is how is the leftNodes/rightNodes value being incremented in the recursive call?
You should think about the end of the recursion.
Suppose you have a single node with no children.
Both left and right would be null, so you will make no recursive calls.
You'll return
leftNodes + rightNodes + 1; // 0 + 0 + 1 == 1
Now, suppose you have a simple tree that consists of a root, a left child and a right child.
When you call nodes() for the root of that tree, both left and right are not null, so we'll call both left.nodes() and right.nodes(). Since both the left and right children are leaf nodes (i.e. they have no children), the recursive calls for both will return 1, as explained above.
Therefore, when the recursive calls return, we'll return
leftNodes + rightNodes + 1; // 1 + 1 + 1 == 3
which is the number of nodes in our tree.
The variables leftNodes and rightNodes are local to the method nodes() which means that there is a different instance of these variables for each call of the method.
So when you call recursively the method (with left.nodes() for instance), the value of leftNodes is the same before and after the recursive call because it (the call) will have it's one instance of leftNodes (and rightNodes).
This is a basic implementation of inorder traversal. For each node it goes to left child until there is no left child remaining (Because of recursion, think like in each visit of a node it is pushed to a stack). Then it repeats the same procedure for the top of the stack until there is no element left in the stack (Again note that, Stack is used to make things simpler compared to recursion). While doing so, it basically increments the total sum by one for each node it visits.
Related
I'm practicing Java by working through algorithms on leetcode. I just solved the "Construct a binary tree from inorder and postorder traversal" problem and was playing with my code to try to get better performance (as measured by the leetcode compilation/testing). Here is the code I wrote:
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(inorder.length == 1){
TreeNode root = new TreeNode(inorder[0]);
return root;
}
if(inorder.length == 0)
return null;
//int j = inorder.length; //Calculate this once, instead of each time the for loop executes
return reBuild(inorder, postorder, 0, inorder.length - 1, 0, postorder.length - 1);
}
public TreeNode reBuild(int[] inorder, int[] postorder, int inStart, int inEnd, int postStart, int postEnd){ //j passed in as argument here
if(inStart > inEnd)
return null; //base case
int rIndex = 0;
int j = inorder.length;
TreeNode root = new TreeNode(postorder[postEnd]); //Root is the last item in the postorder array
if(inStart == inEnd)
return root; //This node has no children
//for(int i = 0; i < inorder.length; ++i)
for(int i = 0; i < j; ++i){ //Find the next root value in inorder and get index
if(inorder[i] == root.val){
rIndex = i;
break;
}
}
root.left = reBuild(inorder, postorder, inStart, rIndex - 1, postStart, postStart - inStart + rIndex - 1); //Build left subtree
root.right = reBuild(inorder, postorder, rIndex + 1, inEnd, postEnd - inEnd + rIndex, postEnd - 1); //Build right subtree
return root;
}
}
My question concerns the for loop in the reBuild function. My first submission calculated the length of inorder each time the loop ran, which is obviously inefficient. I then took this out, and stored the length in a variable j, and used that in the for loop instead. This gave me a boost of ~1ms runtime. So far, so good. Then, I tried moving the calculation of j to the buildTree function, rationalizing that I don't need to calculate it in each recursive call since it doesn't change. When I moved it there and passed it in as a parameter, my runtime went back up 1ms, but my memory usage decreased significantly. Is this a quirk of how leetcode measures efficiency? If not, why would that move increase runtime?
If by calculating the length you mean accessing inorder.length then this is likely why you are losing performance.
When created, arrays hold onto a fixed value for their length called "length". this is a value not a method(thus no real performance used).
If j is never changed (ie j always equals inorder.length) The compiler likely ignores "j = inorder.length;" and simply accesses inorder.length when it sees j. you are then adding complexity to the function call by passing j where inorder (and thus inorder.length) is also present. Though this depends on the compiler implementation and may not actually happen.
In terms of access time, I think public object variables are slower than in-scope variables (think access inorder then access length).
warning hardware talk:
Another thing to consider is registers. These are data storage locations on the CPU itself which the code is actually run from (think HDD/SSD>RAM>cache>registers) and generally cant hold much more than 100 values at a time. Thus depending on the size of the current method (number of variables in scope) the code can run much faster or slower. Java seems to add a lot of overhead to this so for small functions, 1 or 2 extra values in scope can drastically affect the speed (as the program has to access cache).
Wrote a recursive solution for the height of a binary search tree that uses in-order traversal.
Every time the function reaches a "null" node (the end of a line), it resets the variable called "numLevels". Every time the method reaches the end of a line, if numLevels > finalVar, then finalVar becomes numLevels.
This is my solution:
static int finalVar= 0;
static int numLevels= 0;
public static int height(Node root) {
// traverse (in order), ml++ with every recursive call, reset when node == null
findHeight(root);
if (finalVar-1 == 1) return 0; // special case defined in instructions
else{
return finalVar-1;
}
}
public static void findHeight(Node node){
numLevels++; // every time we recursive call, we add
if (node == null){
if (numLevels > finalVar){
finalVar=numLevels;
}
numLevels=0;
return;
}
findHeight(node.left);
findHeight(node.right);
}
and these are the two test cases that it isn't passing:
and:
all the other test cases are passing. Can anyone spot the reason it's not working? :( thanks!
Just spitballing, but wouldn't setting numLevels to 0 also reset it for the other branch? Because remember that your recursive call goes all the way down the furthest left branch, then the branch to the right of the last left. numLevels at that time is 0, which would never be bigger than the other branch.
Since you're making a helper function anyways, there is no reason to have static variables. Just pass along the current max, and the count, and then do everything the same. That way, your current depth is "thread safe" in respect to your recursive depth.
I have made a small program that uses JavaParser [1] to parse Java code and identify the types of statements that appear in the code. This has been implemented successfully. What I want to do next, and is a bit tricky, is to find the parent node for an if-statement, and check whether the first statement of the parent node is a while-loop. After confirming that the above statement is true, I also want to find if this if-statement is the last child of the parent node.
Following you can find an example of the above description:
void example() {
int x = 1;
int y = 1;
while (y < 3) {
while (x < 4) {
x++;
}
if (y < 5) {
y++;
}
}
x = 0;
}
The main question I have with parsing the above code, is how to obtain that the parent node of if (y < 5 ) is a while-loop (while (y < 3)) and secondly, which might be even trickier, is how to identify that the if-statement of this example is the last statement before we skip back to the parent loop. There is also y++; inside the if but it might be skipped if the condition of the if is not true, so I do not want to consider it as the last child of the parent node. I believe what I should do is to check for the last "neighbour"? What I mean by neighbour is the relationship between the second while and the if of this example, i.e. they are at the same level.
My thoughts so far implemented:
//find if the if-statement has a parent node
if (currIf.getParentNode().isPresent()) {
//find if the parent Node is a While loop
Optional<Node> parent = currIf.getParentNode();
parent.get().getBegin();
}
With the above code I am able to check if the if-statement has a parent node and I can find the location of the first while but I do not know how to confirm that it is a while statement and also implement the second described part.
UPDATE:
I managed to find how to check if the parent is a while-loop and currently trying to find a solution on how to identify that the if-statement is the last statement of its level (or hierarchy if you prefer).
Optional<WhileStmt> ifParent = currIf.findAncestor(WhileStmt.class);
//find if the if-statement has a parent node
if (ifParent.isPresent()) {
//find if the parent Node is a While loop
Optional<Node> sameNode = ifParent.get().findFirst(Node.class, n -> n == currIf);
if (sameNode.isPresent()) {
System.out.println(sameNode);
}
}
Your update could give you the wrong result if I am understanding it correctly. Yes, your solution will work if a WhileStmt is the parent, but it also could give you a WhileStmt a bit further up the tree.
Why can't you do something like the following?
boolean parentIsWhileLoop = ifStmtNode.getParent() instanceof WhileStmt;
For determining if the ifStmt is the last node, you could do
Node ifStmtParent = ifStmt.getParent();
List<Node> ifStmtSibilings = ifStmtParent.getChildNodes();
Node lastNode = ifStmtSiblings.get(ifStmtSiblings.size() - 1);
boolean ifStmtIsLast = lastNode == ifStmt;
I am trying to understand the concept of recursion. I understand how it works if there is one recursive statement in the code (example factorial)
I dont understand how code like this to calculate the depth of a binary tree would work:
public int getDepth(Node root)
{
if ( root == null) return 0;
int left = getDepth(root.left);
int right = getDepth(root.right);
if (left > right)
return left + 1;
else
return right + 1;
}
I see why this works but not how. Can someone explain to me how the second recursive call (getDepth(root.right)) works? What would this code look like in the memory? When getDepth(root.left) is recursive called does that stack ever go to the if statement at the every bottom?
What happens is that each consecutive call to getDepth is completely separate and thus the bound variables are separate and it follows it's arguments and is oblivious that it's called from a version of itself with different arguments.
When you do getDepth(null) you get 0 since it's the very base case on the first line. However if you send it getDepth(new Node(null, null)) it will call getDepth(root.left) which is the same as getDepth(null) and turns into 0 for both left and right and the result is 0 + 1.
If you would bind the previous node to a variable node and try getDepth(new Node(node, node)) it will do both left and right again where both of them would be the answer of the previous test 1. The result would be 1 + 1, thus 2.
You can continue like this and just assume the result based on the previous calculations. By looking from a complex argument you need to imagine that each consecutive recursion starts fresh with it's arguments and that follows the same pattern. When a result is passed back the caller continues to the next line. In a tree structure like:
1
/ \
2 3
/\ /\
4 5 6 7
I just numbered the nodes and not included null nodes. You'll see the execution goes in this order. Identation indicates stack depth / how many calls are waiting to be resumed.
getDepth(1)
getDepth(2) // left
getDepth(4) // left
getDepth(null) // left base
getDepth(null) // right base
return 0
getDepth(5) // right
getDepth(null) // left base
getDepth(null) // right base
return 0
return 0 + 1;
getDepth(3) // right
getDepth(6) // left
getDepth(null) // left base
getDepth(null) // right base
return 0
getDepth(7) // right
getDepth(null) // left base
getDepth(null) // right base
return 0
return 0 + 1;
return 1 + 1;
return 2 + 1;
Try to trace the execution if the tree consisted of only a single node (just the root node).
The stack would look something like this when getDepth(root.left) is called:
--->getDepth(root.left) //this will return 0 immediately, and will be popped of the stack
getDepth(root) // this is your entry point
once, getDepth(root.left) returns, the stack looks like this:
--->getDepth(root) // this is your entry point
then the method at the top of the stack now will continue it's execution from where it was (it will now call getDepth(root.right), and the stack will look like this:
--->getDepth(root.right) //this will return 0 immediately, and will be popped of the stack
getDepth(root) // this is your entry point
again, once getDepth(root.right) returns, it will be popped off the stack and the calling method will continue it's execution and will then execute the last if statement.
The same pattern of execution will be followed for a tree with multiple nodes: eventually the recursive method calls will return (unless there is an exception) and the calling method will continue it's execution from the next statement.
I have a n-ary tree which contains key values (integers) in each node. I would like to calculate the minimum depth of the tree. Here is what I have come up with so far:
int min = 0;
private int getMinDepth(Node node, int counter, int temp){
if(node == null){
//if it is the first branch record min
//otherwise compare min to this value
//and record the minimum value
if(counter == 0){
temp = min;
}else{
temp = Math.min(temp, min);
min = 0;
}
counter++;//counter should increment by 1 when at end of branch
return temp;
}
min++;
getMinDepth(node.q1, counter, min);
getMinDepth(node.q2, counter, min);
getMinDepth(node.q3, counter, min);
getMinDepth(node.q4, counter, min);
return temp;
}
The code is called like so:
int minDepth = getMinDepth(root, 0, 0);
The idea is that if the tree is traversing down the first branch (branch number is tracked by counter), then we set the temp holder to store this branch depth. From then on, compare the next branch length and if it smaller, then make temp = that length. For some reason counter is not incrementing at all and always staying at zero. Anyone know what I am doing wrong?
I think you're better off doing a breadth-first search. Your current implementation tries to be depth-first, which means it could end up exploring the whole tree if the branches happen to be in an awkward order.
To do a breadth-first search, you need a queue (a ArrayDeque is probably the right choice). You'll then need a little class that holds a node and a depth. The algorithm goes a little something like this:
Queue<NodeWithDepth> q = new ArrayDeque<NodeWithDepth>();
q.add(new NodeWithDepth(root, 1));
while (true) {
NodeWithDepth nwd = q.remove();
if (hasNoChildren(nwd.node())) return nwd.depth();
if (nwd.node().q1 != null) q.add(new NodeWithDepth(nwd.node().q1, nwd.depth() + 1));
if (nwd.node().q2 != null) q.add(new NodeWithDepth(nwd.node().q2, nwd.depth() + 1));
if (nwd.node().q3 != null) q.add(new NodeWithDepth(nwd.node().q3, nwd.depth() + 1));
if (nwd.node().q4 != null) q.add(new NodeWithDepth(nwd.node().q4, nwd.depth() + 1));
}
This looks like it uses more memory than a depth-first search, but when you consider that stack frames consume memory, and that this will explore less of the tree than a depth-first search, you'll see that's not the case. Probably.
Anyway, see how you get on with it.
You are passing the counter variable by value, not by reference. Thus, any changes made to it are local to the current stack frame and are lost as soon as the function returns and that frame is popped of the stack. Java doesn't support passing primitives (or anything really) by reference, so you'd either have to pass it as a single element array or wrap it in an object to get the behavior you're looking for.
Here's a simpler (untested) version that avoids the need to pass a variable by reference:
private int getMinDepth(QuadTreeNode node){
if(node == null)
return 0;
return 1 + Math.min(
Math.min(getMinDepth(node.q1), getMinDepth(node.q2)),
Math.min(getMinDepth(node.q3), getMinDepth(node.q4)));
}
Both your version and the one above are inefficient because they search the entire tree, when really you only need to search down to the shallowest depth. To do it efficiently, use a queue to do a breadth-first search like Tom recommended. Note however, that the trade-off required to get this extra speed is the extra memory used by the queue.
Edit:
I decided to go ahead and write a breadth first search version that doesn't assume you have a class that keeps track of the nodes' depths (like Tom's NodeWithDepth). Once again, I haven't tested it or even compiled it... But I think it should be enough to get you going even if it doesn't work right out of the box. This version should perform faster on large, complex trees, but also uses more memory to store the queue.
private int getMinDepth(QuadTreeNode node){
// Handle the empty tree case
if(node == null)
return 0;
// Perform a breadth first search for the shallowest null child
// while keeping track of how deep into the tree we are.
LinkedList<QuadTreeNode> queue = new LinkedList<QuadTreeNode>();
queue.addLast(node);
int currentCountTilNextDepth = 1;
int nextCountTilNextDepth = 0;
int depth = 1;
while(!queue.isEmpty()){
// Check if we're transitioning to the next depth
if(currentCountTilNextDepth <= 0){
currentCountTilNextDepth = nextCountTilNextDepth;
nextCountTilNextDepth = 0;
depth++;
}
// If this node has a null child, we're done
QuadTreeNode node = queue.removeFirst();
if(node.q1 == null || node.q2 == null || node.q3 == null || node.q4 == null)
break;
// If it didn't have a null child, add all the children to the queue
queue.addLast(node.q1);
queue.addLast(node.q2);
queue.addLast(node.q3);
queue.addLast(node.q4);
// Housekeeping to keep track of when we need to increment our depth
nextCountTilNextDepth += 4;
currentCountTilNextDepth--;
}
// Return the depth of the shallowest node that had a null child
return depth;
}
Counter is always staying at zero because primitives in java are called by value. This means if you overwrite the value in a function call the caller won't see the change. Or if you're familiar with C++ notation it's foo(int x) instead of foo(int& x).
One solution would be to use an Integer object since objects are call-by-reference.
Since you're interested in the minimum depth a breadth first solution will work just fine, but you may get memory problems for large trees.
If you assume that the tree may become rather large an IDS solution would be the best. This way you'll get the time complexity of the breadth first variant with the space complexity of a depth first solution.
Here's a small example since IDS isn't as well known as its brethren (though much more useful for serious stuff!). I assume that every node has a list with children for simplicity (and since it's more general).
public static<T> int getMinDepth(Node<T> root) {
int depth = 0;
while (!getMinDepth(root, depth)) depth++;
return depth;
}
private static<T> boolean getMinDepth(Node<T> node, int depth) {
if (depth == 0)
return node.children.isEmpty();
for (Node<T> child : node.children)
if (getMinDepth(child, depth - 1)) return true;
return false;
}
For a short explanation see http://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search