First of all, I swear this is not homework, it's a question I was asked in an interview. I think I made a mess of it (though I did realise the solution requires recursion). Here is the question:
Implement the count() method which returns the number of nodes in a tree. If a node doesn't have either a left or right child, the relevant getXXChild() method will return null
class Tree {
Tree getRightChild() {
// Assume this is already implemented
}
Tree getLeftChild() {
// Assume this is already implemented
}
int count() {
// Implement me
}
}
My reason for asking the question is simply curious to see the correct solution, and thereby measure how bad mine was.
Cheers,
Tony
int count() {
Tree right = getRightChild();
Tree left = getLeftChild();
int c = 1; // count yourself!
if ( right != null ) c += right.count(); // count sub trees
if ( left != null ) c += left.count(); // ..
return c;
}
A trivial recursive solution:
int count() {
Tree l = getLeftTree();
Tree r = getRightTree();
return 1 + (l != null ? l.count() : 0) + (r != null ? r.count() : 0);
}
A less trivial non-recursive one:
int count() {
Stack<Tree> s = new Stack<Tree>();
s.push(this);
int cnt = 0;
while (!s.empty()) {
Tree t = s.pop();
cnt++;
Tree ch = getLeftTree();
if (ch != null) s.push(ch);
ch = getRightTree();
if (ch != null) s.push(ch);
}
return cnt;
}
The latter is probably slightly more memory-efficient, because it replaces recursion with a stack and an iteration. It's also probably faster, but its hard to tell without measurements. A key difference is that the recursive solution uses the stack, while the non-recursive solution uses the heap to store the nodes.
Edit: Here's a variant of the iterative solution, which uses the stack less heavily:
int count() {
Tree t = this;
Stack<Tree> s = new Stack<Tree>();
int cnt = 0;
do {
cnt++;
Tree l = t.getLeftTree();
Tree r = t.getRightTree();
if (l != null) {
t = l;
if (r != null) s.push(r);
} else if (r != null) {
t = r;
} else {
t = s.empty() ? null : s.pop();
}
} while (t != null);
return cnt;
}
Whether you need a more efficient or a more elegant solution naturally depends on the size of your trees and on how often you intend to use this routine. Rembemer what Hoare said: "premature optimization is the root of all evil."
I like this better because it reads:
return count for left + count for rigth + 1
int count() {
return countFor( getLeftChild() ) + countFor( getRightChild() ) + 1;
}
private int countFor( Tree tree ) {
return tree == null ? 0 : tree.count();
}
A little more towards literate programming.
BTW, I don't like the getter/setter convention that is so commonly used on Java, I think a using leftChild() instead would be better:
return countFor( leftChild() ) + countFor( rightChild() ) + 1;
Just like Hoshua Bloch explains here http://www.youtube.com/watch?v=aAb7hSCtvGw at min. 32:03
If you get it rigth your code reads...
BUT, I have to admit the get/set convention is now almost part of the language. :)
For many other parts, following this strategy creates self documenting code, which is something good.
Tony: I wonder, what was your answer in the interview.
return (getRightChild() == null ? 0 : getRightChild.count()) + (getLeftChild() == null ? 0 : getLeftChild.count()) + 1;
Or something like that.
Something like this should work:
int count()
{
int left = getLeftChild() == null ? 0 : getLeftChild().count();
int right = getRightChild() == null ? 0 : getRightCHild().count();
return left + right + 1;
}
class Tree {
Tree getRightChild() {
// Assume this is already implemented
}
Tree getLeftChild() {
// Assume this is already implemented
}
int count() {
return 1
+ getRightChild() == null? 0 : getRightChild().count()
+ getLeftChild() == null? 0 : getLeftChild().count();
}
}
You can count the tree by traversing it many ways. Simply preorder traversal, the code would be (based on the functions you defined):
int count() {
count = 1;
if (this.getLeftChild() != null)
count += this.getLeftChild().count();
if (this.getRightChild() != null)
count += this.getRightChild().count();
return count;
}
Implement the method:
public static int countOneChild(Node root)
{
...
}
that counts the number of internal nodes in a binary tree having one child. Add the function to tree.java program.
I did it by preorder recurssion. Altough it doesn't exactly follow the interview format by using localRoot, but I think you get the idea.
private int countNodes(Node<E> localRoot, int count) {
if (localRoot == null)
return count;
count++; // Visit root
count = countNodes(localRoot.left, count); // Preorder-traverse (left)
count = countNodes(localRoot.right, count); // Preorder-traverse (right)
return count;
}
public int countNodes() {
return countNodes(root, 0);
}
This is a standard recursion problem:
count():
cnt = 1 // this node
if (haveRight) cnt += right.count
if (haveLeft) cnt += left.count
return cnt;
Very inefficient, and a killer if the tree is very deep, but that's recursion for ya...
int count()
{
int retval = 1;
if(null != getRightChild()) retval+=getRightChild().count();
if(null != getLeftChild()) retval+=getLeftChild().count();
return retval;
}
God I hope I didn't make a mistake.
EDIT: I did actually.
Of course, if you want to avoid visiting every node in your tree when you count, and processing time is worth more to you than memory, you can cheat by creating your counts as you build your tree.
Have an int count in each node,
initialized to one, which
respresents the number of nodes in
the subtree rooted in that node.
When you insert a node, before
returning from your recursive insert
routine, increment the count at the
current node.
i.e.
public void insert(Node root, Node newNode) {
if (newNode.compareTo(root) > 1) {
if (root.right != null)
insert(root.right, newNode);
else
root.right = newNode;
} else {
if (root.left != null)
insert(root.left, newNode);
else
root.left = newNode;
}
root.count++;
}
Then getting the count from any point just involves a lookup of node.count
My first attempt didn't have anything new to add, but then I started to wonder about recursion depth and whether it would be possible to rearrange the code to take advantage of the tail call optimization feature of the latest Java compiler. The main problem was the null test - which can be solved using a NullObject. I'm not sure if TCO can deal with both recursive calls, but it should at least optimize the last one.
static class NullNode extends Tree {
private static final Tree s_instance = new NullNode();
static Tree instance() {
return s_instance;
}
#Override
Tree getRightChild() {
return null;
}
#Override
Tree getLeftChild() {
return null;
}
int count() {
return 0;
}
}
int count() {
Tree right = getRightChild();
Tree left = getLeftChild();
if ( right == null ) { right = NullNode.instance(); }
if ( left == null ) { left = NullNode.instance(); }
return 1 + right.count() + left.count();
}
The precise implementation of NullNode depends on the implementations used in Tree - if Tree uses NullNode instead of null, then perhaps the child access methods should throw NullPointerException instead of returning null. Anyway, the main idea is to use a NullObject in order to try to benifit from TCO.
Questions related to binary tree should be expected in an interview. I would say to take time before any next interview and go through this link. There are about 14 problems solved .You can have a look and how the solution is done. This would give you an idea of how to tackle a problem with binary tree in future.
I know your question is specific to the count method .That is also implemented in the link that i provided
class Tree {
Tree getRightChild() {
// Assume this is already implemented
}
Tree getLeftChild() {
// Assume this is already implemented
}
int count() {
if(this.getLeftChild() !=null && this.getRightChild()!=null)
return 1 + this.getLeftChild().count() + this.getRightChild().count();
elseif(this.getLeftChild() !=null && this.getRightChild()==null)
return 1 + this.getLeftChild().count();
elseif(this.getLeftChild() ==null && this.getRightChild()!=null)
return 1 + this.getRightChild().count();
else return 1;//left & right sub trees are null ==> count the root node
}
}
Related
As for my question: I have a Node class:
public class Node<E> {
private E value;
private Node<E> left;
private Node<E> right;
public Node(E value) {
this.value = value;
this.left = null;
this.right = null;
}
and this class has two methods which calculate the depth of the node (binary tree). The method totaldepth() I wrote myself and it gives an incorrect answer, for which I need your help debugging. The method maxDepth(Node node) gives the correct answer and was used as reference material by me. Could you help me debug totalDepth method as to me it looks the same as maxDepthby the result.
incorrect code:
public int totalDepth() {
// initialize variabele depth
int depth = 0;
// reached leaf return 0
if (right == null && left == null) {
return 0;
}
// not yet reached leaf, continue deeper
else {
int leftdepth = 0;
int rightdepth = 0;
// left node is not null continue going left
if (left != null) {
leftdepth = left.totalDepth();
}
// right node is not null continue going right
if (right != null) {
rightdepth = right.totalDepth();
}
if (leftdepth > rightdepth) {
// 1 is needed because each call to totalDepth raises depth by 1
depth = leftdepth + 1;
}
else {
depth = rightdepth + 1;
}
}
return depth;
}
correct code:
public int maxDepth(Node node) {
if (node == null) {
return (0);
}
else {
// compute the depth of each subtree
int leftDepth = maxDepth(node.left);
int rightDepth = maxDepth(node.right);
// use the larger one
if (leftDepth > rightDepth)
return (leftDepth + 1);
else
return (rightDepth + 1);
}
}
Also I'm just starting to learn how to code so forgive me for all the inefficient things I'm doing. Thanks in advance for helping me!
Your totalDepth method will not work, because you have a tree, and you don't actually know, how many elements you have from the left and the right. Balanced this tree or not. So, only way to walk throw the tree, is to use Breadth-first search or Depth-first search algorithm, and they are based of recursion function like maxDepth(Node node) method.
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
}
THIS IS HOMEWORK, DO NOT POST CODE. Please and thank you.
I have been assigned to create a method that calculates the depth of a particular in a BST.
To do this, I am to #Override a method public int depth(T data). So, to find it recursively, I need to create a helper method.
I know that I need to essentially search the tree for the node with the data I'm looking for. So, to do this, I've written the following code:
#Override
public int depth(T data) {
if (data == null) {
throw new IllegalArgumentException("Data is null");
}
if (compare(data, root.getData()) == 0) {
return 1;
} else {
return countNodes(search(root, data), data);
}
}
private int countNodes(BSTNode<T> node, T data) {
int depth = 1;
if (node == null) {
return 0;
} else {
if (compare(data, node.getData()) == 0) {
return depth;
} else if (compare(data, node.getData()) < 0) {
return countNodes(node.getLeft(), data);
} else {
return countNodes(node.getRight(), data);
}
}
}
private int compare(T a, T b) {
return a.compareTo(b);
}
However, this isn't going to work, as depth would remain 1 each time the recursive call is made; essentially, it's resetting the value of depth. I have no idea how to keep the value of depth in-between calls.
Your depth method should return one if the current node is the one you are looking for or the depth of the next node down plus one if you need to keep looking.
For example:
N5
N3 N7
N1 N4 N6
You want to know the depth of N1.
You start at the root:
N1 != N5 so you return one plus the result of your check on N3. (1 + (result of N3 check))
N1 != N3 so you return one plus the result of your check on N1. (1 + (1 + (result of N1 check)))
N1 == N1 so you you return one. (1 + (1 + (1)))
(1 + (1 + (1))) = 3
this is the correct depth and is what the initial depth call will return.
Many answers on the net for 'finding Least Common Ancestor in binary tree' and its supplementary question 'find distance between 2 nodes' have 4 issues:
Does not consider duplicates
Does not consider if input node is invalid/absent/not in tree
Use extra / aux storage
Not truncating the traversal although answer is obtained.
I coded this sample to overcome all handicaps. but since I did not find 'a single' answer in this direction, I would appreciate if my code has a significant disadvantage which I am missing. Maybe there is none. Additional eyeballs appreciated.
public int distance(int n1, int n2) {
LCAData lcaData = new LCAData(null, 0, 0);
int distance = foundDistance (root, lcaData, n1, n2, new HashSet<Integer>());
if (lcaData.lca != null) {
return distance;
} else {
throw new IllegalArgumentException("The tree does not contain either one or more of input data. ");
}
}
private static class LCAData {
TreeNode lca;
int count;
public LCAData(TreeNode parent, int count) {
this.lca = parent;
this.count = count;
}
}
private int foundDistance (TreeNode node, LCAData lcaData, int n1, int n2, Set<Integer> set) {
assert set != null;
if (node == null) {
return 0;
}
// when both were found
if (lcaData.count == 2) {
return 0;
}
// when only one of them is found
if ((node.item == n1 || node.item == n2) && lcaData.count == 1) {
// second element to be found is not a duplicate node of the tree.
if (!set.contains(node.item)) {
lcaData.count++;
return 1;
}
}
int foundInCurrent = 0;
// when nothing was found (count == 0), or a duplicate tree node was found (count == 1)
if (node.item == n1 || node.item == n2) {
if (!set.contains(node.item)) {
set.add(node.item);
lcaData.count++;
}
// replace the old found node with new found node, in case of duplicate. this makes distance the shortest.
foundInCurrent = 1;
}
int foundInLeft = foundDistance(node.left, lcaData, n1, n2, set);
int foundInRight = foundDistance(node.right, lcaData, n1, n2, set);
// second node was child of current, or both nodes were children of current
if (((foundInLeft > 0 && foundInRight > 0) ||
(foundInCurrent == 1 && foundInRight > 0) ||
(foundInCurrent == 1 && foundInLeft > 0)) &&
lcaData.lca == null) {
// least common ancestor has been obtained
lcaData.lca = node;
return foundInLeft + foundInRight;
}
// first node to match is the current node. none of its children are part of second node.
if (foundInCurrent == 1) {
return foundInCurrent;
}
// ancestor has been obtained, aka distance has been found. simply return the distance obtained
if (lcaData.lca != null) {
return foundInLeft + foundInRight;
}
// one of the children of current node was a possible match.
return (foundInLeft + foundInRight) > 0 ? (foundInLeft + foundInRight) + 1 : (foundInLeft + foundInRight);
}
The algorithm appears to be (without pulling it apart entirely) to exhaustively traverse the entire tree until a node is found where there is one node found on the left and one on the right. And creating an additional set as you go.
The problem here seems to be that your algorithm is very inefficient. That may fit your requirements, if this particular operation is almost never carried out. But normally you could do better.
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 );
}
}