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.
Related
In my program, I have initialized a binary tree and I want to search if a node exists in that binary tree. If it does exist, then I will print the subtree of that node and the level it was found. I am able to perform my search method but I am not sure how to print the subtree of that node found and its level.
For example, this is my binary tree [K=3 L=[K=1 R=[K=2]] R=[K=5 L=[K=4]]. If I search for node 1, then it will return the node (not null) since it exists in my binary tree.
Problem: I need to print only the subtree of the node and the level where it was found: [K=1 R=[K=2]], level=1.
Here is my source code for reference:
Main Class
// instantiate BST object
BST<Character> bst = new BST<>();
// insert values to bst1
String str = "31254";
char[] letter = str.toCharArray();
for (int i = 0; i < letter.length; i++) {
Character c = letter[i];
bst1.insert(c);
}
// print bst
System.out.println("\nht=" + bst1.height + " " + bst1.toString() + "\n");
// search values in bst1
String str2 = "016483";
char[] letter2 = str2.toCharArray();
for (int i = 0; i < letter2.length; i++) {
Character c = letter2[i];
if (bst1.search(c) != null) { // if found, print the node (w/ subtree) and its level
// ** part that should print the subtree and its level
}
else {
System.out.println(c + " is not found.");
}
}
BST Class - where my search method is declared
public class BST<T extends Comparable<T>> extends BT<T> {
// insert() method
// search method
public BTNode<T> search(T k) {// my method
BTNode<T> n = root;
while (n != null) {
if (n.info.compareTo(k) == 0) {
return n;
}
else {
if (n.info.compareTo(k) > 0) {
n = n.left;
}
else {
n = n.right;
}
}
}
return null;
}
}
Thanks in advance!
I did not modify your code. Instead, I used an imaginary class Node that I've written. Also, I have written all of them as half pseudo half java code.
Suppose your node has only one int type variable and two children.
class Node{
int data;
Node left;
Node right;
}
You have a printExistingSubTree method in your BST class that does the what you exactly ask for:
printExistingSubTree(Node node, int key):
if (find(node.left, key, 0) != -1)
then
printTree(node.left)
print(find(node.left, key, 0))
if (find(node.right, key, 0) != -1)
then printTree(node.right)
printTree(node.right)
print(find(node.right, key, 0))
You have a find method in your BST class that does find the index:
int find(Node node,int key, int level)
if(node.data is equal to the key)
then return level
int left = -1;
if(node.leftChild is not null)
then left = find(node.left, key, level+1)
if(left != -1)
return left
int right = -1;
if(node.rightChild is not null)
then right = find(node.right, key, level+1)
return right
Then, to print, you should decide how you want to traverse the subtree.
You have a printTree method in your BST class that prints the subtree in postorder:
void printTree(Node node){
if (node == null)
return;
printTree(node.left);
printTree(node.right);
print(node.data + " ");
}
Note: I did not understand your whole code. Therefore, I have just written the answer of your question in the pseudo code format. I think, you can write your own code from that.
Note2: There may be some typos&wrong namings. PLease do not lynch. Just write in the comments and I'll correct.
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.
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'm trying to write a method for the maximum sum of a path through a binary tree:
public class ConsTree<T> extends BinaryTree<T>
{
BinaryTree<T> left;
BinaryTree<T> right;
T data;
public int maxSum()
{
}
}
As is shown, each tree contains a tree to its left and to its right, as well as a data of a generic type. I am somewhat confused on how to go about starting this. If someone could provide help as to what the algorithm might look like or put me in the right direction, that would be great. Thanks.
The way to think recursively is to consider the cases. In our case, we look at a single node and can decide what paths it has:
If the node has no children, then the only path is the singleton path (consisting of that node by itself).
If the node has only one child, then all paths go through that child.
Otherwise, the node has two children. Then, all paths go through one of its two children.
In case 1, the maximum must be that node's value. In case 2, the maximum is that node's value, plus the max-path-sum of its child (since that path is extended to a path for the parent through the only child). In case 3, the maximum is the maximum max-path-sum of its two children (since the best path must go through one of the two children, and the parent can see which of the children's best paths is better).
Therefore, the code is really simple. Here, since you return an int, I'm going to assume T = int.
public int maxSum() {
/* case 1 */
if(left == null && right == null)
return data;
/* case 2 */
if(right == null)
return data + left.maxSum();
else if(left == null)
return data + right.maxSum();
/* case 3 */
return Math.max(data + left.maxSum(), data + right.maxSum());
}
private static int max = Integer.MIN_VALUE;
public static int maxPathSum(TreeNode root) {
int rd = dfs(root);
return rd > max ? rd : max;
}
// close paths:
// 1 left leaf
// 2 right leaf
// 3 left + root + right
//
// open paths:
// 4 root
// 5 left + root
// 6 right + root
private static int dfs(TreeNode root) {
if (root.left == null && root.right == null) {
return root.val;
}
if (root.left == null && root.right != null) {
int rPathMax = dfs(root.right);
max = rPathMax > max ? rPathMax : max;
return Math.max(root.val, rPathMax + root.val);
}
if (root.right == null && root.left != null) {
int lPathMax = dfs(root.left);
max = lPathMax > max ? lPathMax : max;
return Math.max(root.val, lPathMax + root.val);
}
int lPathMax = dfs(root.left);
int rPathMax = dfs(root.right);
int closePathMax = lPathMax + rPathMax + root.val;
int innerMax = Math.max(closePathMax, Math.max(lPathMax, rPathMax));
max = innerMax > max ? innerMax : max;
return Math.max(root.val, Math.max(lPathMax + root.val, rPathMax + root.val));
}
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
}
}