In a binary tree BFS algorithm, can someone please help me understand why we do a height - 1 in the code below. I wrote this code but it never worked until I figured out online you need to do a height - 1.
public class BreadthFirstSearch {
public static int calculateHeightOfTree(Node root) {
if (root == null) {
return 0;
} else {
return 1 + Math.max(calculateHeightOfTree(root.leftNode), calculateHeightOfTree(root.rightNode));
}
}
public static void printDataAtAllLevels(Node root, int height) {
for (int i = 1; i <= height; i++) {
printDataAtGivenLevel(root, i);
}
}
public static void printDataAtGivenLevel(Node root, int height) {
if (root == null) {
return;
}
if (height == 1) {
System.out.println(root.data);
} else {
printDataAtGivenLevel(root.leftNode, height - 1);
printDataAtGivenLevel(root.rightNode, height - 1);
}
}
public static void main(String[] args) {
Node node = new Node(1);
node.leftNode = new Node(2);
node.rightNode = new Node(3);
node.leftNode.leftNode = new Node(4);
node.leftNode.rightNode = new Node(5);
System.out.println("Level order traversal of binary tree is ");
int height = calculateHeightOfTree(node);
System.out.println("HEIGHT: " + height);
printDataAtAllLevels(node, height);
}
Well, if you want to print the data of level n of the tree, that's equivalent to printing the data of level n-1 of the left and right sub-trees. Therefore, when you pass the left and right sub-trees to the recursive calls, you should request to print the data of level reduced by 1.
For example, since the root of the tree has level 1, the left and right children of the root have level 2.
So if you wish to print all the data of level 2 for the original tree, that's equivalent to printing the data of level 1 for the left and right sub-trees.
If you would not decrease height it would always be the same value in every (recursive) method call.
Therefore the recursion would not stop because height == 1 would always be false. It would only stop because root == null would be true, because you reached the end of a sub-tree. But in this case there would be no output, but only a return.
Because the height int printDataAtGivenLevel(Node root, int height) is the height relative to the root. So if you want to print level 2 from the root, you need to print level 1 from root.left and root.right.
So that you can print the height starting from the node with the lowest height to the node with the maximum height.
Honestly, when I read Binary tree breadth first search algorithm, I do not think about a series of depth-limited DFS traversals, but visiting nodes of a given level, and collecting the ones for the next level, rinse and repeat:
static void doStuff(Node root){
List<Node> current=new ArrayList<>();
current.add(root);
int level=0;
int total=0;
while(current.size()>0){
level++;
System.out.println("Level "+level+":");
List<Node> next=new ArrayList<>();
for(int i=0;i<current.size();i++){
Node node=current.get(i);
System.out.print(node.data+" ");
if(node.leftNode!=null)
next.add(node.leftNode);
if(node.rightNode!=null)
next.add(node.rightNode);
total++;
}
System.out.println();
current=next;
}
System.out.println(total+" nodes visited, from "+level+" levels");
}
Then it can be tricked into one list:
static void doStuff(Node root){
List<Node> nodes=new LinkedList<>();
nodes.add(root);
int level=0;
int total=0;
int current;
while((current=nodes.size())>0){
level++;
System.out.println("Level "+level+":");
while(current-->0){
Node node=nodes.removeFirst();
System.out.print(node.data+" ");
if(node.leftNode!=null)
nodes.add(node.leftNode);
if(node.rightNode!=null)
nodes.add(node.rightNode);
total++;
}
System.out.println();
}
System.out.println(total+" nodes visited, from "+level+" levels");
}
Related
I am working on Leetcode question 437 Path Sum III, and solving it use DFS on java:
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public static int pathSum(TreeNode root, int sum) {
return dfs(root, sum)+pathSum(root.left, sum)+pathSum(root.right, sum);
}
public static int dfs(TreeNode root, int sum) {
if (root == null) return 0;
int count = 0;
if (root.val == sum) count++;
count += dfs(root.left, sum - root.val);
count += dfs(root.right, sum - root.val);
return count;
}
In the return statement of pathSum() method, why we need "dfs(root, sum)+dfs(root.left, sum)+dfs(root.right, sum)", not simply "dfs(root, sum)(this one returns wrong answer)"?
Someone explains that is because "The path does not need to start or end at the root or a leaf "(from lc437). If so, then why we only need to also only check root's children, not also the children of root's children?
To avoid NullPointerException you need to make a small change in pathSum:
public static int pathSum(TreeNode root, int sum) {
if( root == null) return 0;
return dfs(root, sum)+pathSum(root.left, sum)+pathSum(root.right, sum);
}
Consider the given tree:
Now let's transverse the tree from the root node searching for a path with a length of 8.
This can do it by omitting +pathSum(root.left, sum)+pathSum(root.right, sum); from pathSum:
public static int pathSum(TreeNode root, int sum) {
if( root == null) return 0;
//check root only
return dfs(root, sum);//+pathSum(root.left, sum)+pathSum(root.right, sum);
}
This return 0 because there is no path, starting at the root, with the length of 0.
So now we want to check the sub trees. Is there any path with a length of 8 starting at root.right ? We can do it like so:
public static int pathSum(TreeNode root, int sum) {
if( root == null) return 0;
//check root, check root.right and return the sum
return dfs(root, sum) + pathSum(root.right, sum) ;//+pathSum(root.left, sum);
}
This should return 1 because there is one path starting atroot.right with the length of 8: -3 -> 11
I hope this clarifies why we need to check root as well as left and right for the complete result.
Side note: you can get the same result by checking all tree node in a non-recursive manner. For example:
Stack<TreeNode> stack = new Stack<>();
stack.add(root);
int count = 0;
while (! stack.isEmpty()){
TreeNode node = stack.pop();
count += dfs(node,8);
if(node != null) {
stack.add(node.left);
stack.add(node.right);
}
}
System.out.println(count);
Because by going left and right on the tree we will traverse it. We have to traverse the tree in order to find the path sum. If you only go to root then you will not move in the tree thus resulting in the wrong answer.
public static int pathSum(TreeNode root, int sum) {
return dfs(root, sum)+pathSum(root.left, sum)+pathSum(root.right, sum);
}
What this does is it treats each of the nodes as the root of a subtree on which it calculates the path and by calculating the sum of the path of the smaller trees you will obtain the sum of the paths of the larger tree.
I hope that this helps.
I have a trie where each node is an object TrieNode like this:
public char content;
public double count;
public LinkedList<TrieNode> childList;
I had to count the height of the trie (root had level = 0).
So this is what I've done:
int levels = getLevels(getRoot());
System.out.println("levels: " + levels);
public int getLevels(TrieNode node) {
int lev = 0;
if(node != null) {
TrieNode current = node;
for(TrieNode child : node.childList) {
lev += getLevels(child);
}
}
return lev;
}
But it returns always 0. Why?
Thanks
You need to add 1 when you descend to children, otherwise nothing gives lev a non-zero value.
Note that you're not calculating the height of the trie in this code, you're summing the lengths of the paths. You need to find the maximum path length:
int lev = 1;
for (TrieNode child : node.childList) {
lev = Math.max(lev, 1 + getLevels(child));
}
I am trying to find the diameter of a binary tree (Path length between any two nodes in the tree containing maximum number of nodes.) in java.
my code snippet:
public int diametre(Node node, int d)
{
if(node==null)
return 0;
lh=diametre(node.left, d);
rh=diametre(node.right, d);
if(lh+rh+1>d)
d=lh+rh+1;
return findMax(lh, rh)+1;
}
In main method:
System.out.println( bst.diametre(root,0) );
Logic:
Its actually post-order logic. variable 'd' refers to the diameter of the sub-tree (In that iteration.). It will be updated as and when some larger value found.
'lh' refers to : Left sub tree's height.
'rh' refers to : right sub tree's height.
But its giving wrong output.
Tree considered:
5
/ \
/ \
1 8
\ /\
\ / \
3 6 9
Idle output: 5
But this code is giving 3.
Can some one figure out where the problem is...
public int diameter (Node root)
{
if (root == null) return 0;
else return Math.max (
diameter (root.left),
Math.max (
diameter (root.right),
height (root.left) + height (root.right) + 1));
}
public int height (Node root)
{
if (root == null) return 0;
else return 1 + Math.max (height (root.left), height (root.right));
}
You find a diameter of a tree by running a BFS from any node and then another BFS from the furthest node(the node last visited during the first BFS). The diameter is formed by the node last visited in the first BFS and the node last visited in the first BFS. The fact that the tree is binary does not affect the algorithm.
EDIT: changing the value of d in the code you have written will not affect the argument you pass as primitive types are not passed by reference in java.
I suggest the following:
public static TreeAttr calcTreeDiameter(Node root) {
if (root == null)
return new TreeAttr(0, 0);
TreeAttr leftAttr = calcTreeDiameter(root.getLeft());
TreeAttr rightAttr = calcTreeDiameter(root.getRight());
int maxDepth = Math.max(leftAttr.depth, rightAttr.depth);
int maxDiam = Math.max(leftAttr.diameter, rightAttr.diameter);
maxDiam = Math.max(maxDiam, leftAttr.depth + rightAttr.depth + 1);
return new TreeAttr(maxDiam, maxDepth + 1);
}
The TreeAttr is a simple structure containing the diameter and depth of a subtree. Both should be passed in the recursion, since the optimum may either come from one of the subtrees, or from the concatenation of the longest paths.
int max=0;
public int diameter(Tree root) {
if(root==null) return 0;
int l=diameter(root.left);
int r=diameter(root.right);
max=Math.max(max,l+r+1);
return l>r:l+1:r+1;
}
max is the max diameter.
Algo takes O(n). Calculates height and path at the same time.
public static int findLongestPath(TreeNode root)
{
// longest path = max (h1 + h2 + 2, longestpath(left), longestpath(right);
int[] treeInfo = longestPathHelper(root);
return treeInfo[0];
}
private static int[] longestPathHelper(TreeNode root)
{
int[] retVal = new int[2];
if (root == null)
{
//height and longest path are 0
retVal[0] = 0;
retVal[1] = 0;
}
int[] leftInfo = longestPathHelper(root.getLeft());
int[] rightInfo = longestPathHelper(root.getRight());
retVal[0] = Math.max(leftInfo[1] + rightInfo[1] + 2, Math.max(leftInfo[0], rightInfo[0]));
retVal[1] = Math.max(leftInfo[1], rightInfo[1]) + 1;
return retVal;
}
You should use the height of the tree to calculate the diameter. Make a getHeight() function which will take the root of the tree as argument and return the height of the tree. Using this value and with the help of recursion we can calculate the diameter of the tree. Here is the code for it.....
Function for calculating the diameter :-
public static int getDiameter(BinaryTreeNode root) {
if (root == null)
return 0;
int rootDiameter = findHeight(root.getLeft()) + findHeight(root.getRight()) + 1;
int leftDiameter = getDiameter(root.getLeft());
int rightDiameter = getDiameter(root.getRight());
return Math.max(rootDiameter, Math.max(leftDiameter, rightDiameter));
}
Function for calculating the height of tree:-
public static int findHeight(BinaryTreeNode node) {
if(node == null)
return 0;
else {
return 1+Math.max(findHeight(node.left), findHeight(node.right));
}
}
Diameter of a Binary Tree in O(n), It will track the diameter passing through root node or not and uses the same height function to track the diameter.
DiameterOfTree.class
import BinaryTree.BinaryTreeNode;
public class DiameterOfBinaryTree {
private int DIAMETER = 0;
public void getDiameterOfBinaryTree(BinaryTreeNode node) {
getHeightUtil(node, DIAMETER);
System.out.print("\n\n Maximum Diameter of the tree is : " + DIAMETER);
}
private int getHeightUtil(BinaryTreeNode node, Integer maXValue) {
if (node == null) {
return 0;
}
// Here we get the maximum value returned + 1 for each subtree left or
// right
int leftHeight = getHeightUtil(node.getLeft(), maXValue);
int rightHeight = getHeightUtil(node.getRight(), maXValue);
//finding the new diameter at a particular node and adding 1 to
//include that particular node as well: leftHeight + rightHeight + 1
DIAMETER = Math.max(DIAMETER, leftHeight + rightHeight + 1);
return 1 + Math.max(leftHeight, rightHeight);
}
}
Main.java
package BinaryTree;
public class Main {
public static void main(String[] args) {
//Initialise root
BinaryTreeNode root = new BinaryTreeNode(40);
//Create a binary Tree
InitialiseBinaryTree initialiseBinaryTree = new InitialiseBinaryTree();
initialiseBinaryTree.initialise(root);
// Find the diameter of the binary tree
new DiameterOfBinaryTree().getDiameterOfBinaryTree(root);
}
}
InitialiseBinaryTree.java
package BinaryTree;
class InitialiseBinaryTree {
void initialise(BinaryTreeNode root) {
BinaryTreeOperation bto = new BinaryTreeOperation();
int[] data = {20, 50, 10, 30, 5,8, 25, 32, 33};
for (int aData : data) {
bto.insertElementInBinaryTree(root, aData);
}
}
}
BinaryTreeOperation.java
package BinaryTree;
class BinaryTreeOperation {
private boolean findInBinaryTree(BinaryTreeNode node, int data) {
return node != null &&
(data == node.getData() || (findInBinaryTree(node.getLeft(), data) || findInBinaryTree(node.getRight(), data)));
}
void insertElementInBinaryTree(BinaryTreeNode node, int data) {
if (node == null) {
new BinaryTreeNode(data);
} else {
insertHelper(node, data);
}
}
private void insertHelper(BinaryTreeNode node, int data) {
if (node.getData() > data) {
if (node.getLeft() == null) {
node.setLeft(new BinaryTreeNode(data));
} else {
insertHelper(node.getLeft(), data);
}
} else {
if (node.getRight() == null) {
node.setRight(new BinaryTreeNode(data));
} else {
insertHelper(node.getRight(), data);
}
}
}
}
So I have a homework question where I'm supposed to use a recursive method to "find the minimum element within a subtree rooted at the specified node"
And then I'm given this as my starting point:
public TreeNode
{
int data;
TreeNode left;
TreeNode right;
}
and
/**
Finds the minimum value for the subtree that is
rooted at a given node
#param n The root of the subtree
#return The minimum value
PRECONDITION: n is not null.
*/
int min(TreeNode n)
{
// COMPLETE THE BODY OF THIS METHOD
}
Now, I've got a very basic driver program written to insert nodes into the tree and I've written my recursive method, but it seems to be counting up instead of down, here's my method:
int min(TreeNode n){
if(n.left != null) {
n = n.left;
min(n);
System.out.println("N is now " + n.value);
}
return n.value;
}
Output of my code:
Building tree with rootvalue 25
=================================
Inserted 11 to left of node 25
Inserted 15 to right of node 11
Inserted 16 to right of node 15
Inserted 23 to right of node 16
Inserted 79 to right of node 25
Inserted 5 to left of node 11
Inserted 4 to left of node 5
Inserted 2 to left of node 4
Root is 25
N is now 2
N is now 4
N is now 5
N is now 11
The minimum integer in the given nodes subtree is: 11
Can someone please explain to me why this doesn't work?
Note: this is all assuming you're in a Binary Search Tree, so returning the minimum element means returning the left-most element.
This means your recursive call is quite simple:
min(node):
if this node has a left node:
return min(node.left)
if this node does not have a left node:
return this node's value
The logic is that if we don't have another left node then we are the left-most node, so we are the minimum value.
Now, in Java:
int min(TreeNode n){
if (n.left == null)
return n.value;
return min(n.left); // n.left cannot be null here
}
Now to explain your results, consider how this method works. It calls the method on the next node (min(n.left)) before continuing. In your case you had a println after this recursive call. Therefore the println inside the recursive call went first. So your prints started at the bottom of the tree and worked their way back up. This explains the "reverse order" printing.
Your method then returned 11 as your result because (as another answer has explained) your n = n.left didn't affect any of your recursive sub-calls, only the one in the current function call. This means you returned the left node of the root, rather than the furthest left child.
I hope this makes sense. If you need clarification on anything leave a comment or something. Recursion can be quite tricky to get your head around at first.
The issue is that Java is call-by-value, not by reference -- although references are passed by value. But what that really means in this case is that the call to min(n) does not change what the variable n refers to -- it doesn't do anything at all. What you should probably be doing is return min(n).
public static void main(String[] args) throws IOException, NoSuchMethodException, InitializationError {
Logger.getRootLogger().addAppender(new ConsoleAppender(new SimpleLayout(), "System.out"));
Logger.getRootLogger().setLevel(Level.ALL);
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
n1.data = 110;
n1.left = n2;
n1.right = n3;
n2.data = 15;
n2.left = n4;
n2.right = null;
n3.data = 3;
n3.left = null;
n3.right = null;
n4.data = 4;
n4.left = null;
n4.right = n5;
n5.data = 12;
n5.left = n6;
n5.right = null;
n6.data = 19;
n6.left = null;
n6.right = null;
System.out.print("min=" + min(n1));
}
static public class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
static int min(TreeNode n) {
return min(n, n.data);
}
static int min(TreeNode n, int min) {
System.out.println("N is now " + n.data);
int currentMin = min;
if (n.left != null && n.right != null) {
final int left = min(n.left);
final int right = min(n.right);
if (left < right) {
currentMin = left;
} else {
currentMin = right;
}
} else if (n.left != null) {
currentMin = min(n.left);
} else if (n.right != null) {
currentMin = min(n.right);
}
if (currentMin < min) {
return currentMin;
} else {
return min;
}
}
OUTPUT is:
N is now 110
N is now 15
N is now 4
N is now 12
N is now 19
N is now 3
min=3
You need to use some tree traversal algoritm, for checking every node of the tree. Also you need to store current finded minimum. Pass this minimum into recursive function. It is calling "accumulator".
The last statement in your method implementation returns the node n's value. As n starts with the root and is replaced by its left child (if exists) you always get the value of the root's left child.
The following code should do it:
int min(final Tree n){
int result;
if(n == null){
result = Integer.MAX_VALUE;
} else {
result = n.value;
final int leftResult = min(n.left);
if(leftResult < result){
result = leftResult;
}
final int rightResult = min(n.right);
if(rightResult < result){
result = rightResult;
}
}
return result;
}
Or you could use the Visitor pattern (you would need to make your tree Iterable then and pass the values to the Visitor one-by-one):
interface TreeVisitor {
void accept(int value);
}
class MinTreeVisistor implements TreeVisitor {
int min = Integer.MAX_VALUE;
#Override
public void accept(int value) {
if(value < this.min) {
this.min = value;
}
}
}
I would like to calculate the summation of the depths of each node of a Binary Search Tree.
The individual depths of the elements are not already stored.
Something like this:
int countChildren(Node node)
{
if ( node == null )
return 0;
return 1 + countChildren(node.getLeft()) + countChildren(node.getRight());
}
And to get the sum of the depths of every child:
int sumDepthOfAllChildren(Node node, int depth)
{
if ( node == null )
return 0; // starting to see a pattern?
return depth + sumDepthOfAllChildren(node.getLeft(), depth + 1) +
sumDepthOfAllChildren(node.getRight(), depth + 1);
}
Now for a hopefully informative explanation in case this is homework. Counting the number of nodes is quite simple. First of all, if the node isn't a node (node == null) it returns 0. If it is a node, it first counts its self (the 1), plus the number of nodes in its left sub-tree plus the number of nodes in its right sub-tree. Another way to think of it is you visit every node via BFS, and add one to the count for every node you visit.
The Summation of depths is similar, except instead of adding just one for each node, the node adds the depth of its self. And it knows the depth of its self because its parent told it. Each node knows that the depth of it's children are it's own depth plus one, so when you get the depth of the left and right children of a node, you tell them their depth is the current node's depth plus 1.
And again, if the node isn't a node, it has no depth. So if you want the sum of the depth of all the root node's children, you pass in the root node and the root node's depth like so: sumDepthOfAllChildren(root, 0)
Recursion is quite useful, it's just a very different way of thinking about things and takes practice to get accustomed to it
int maxDepth(Node node) {
if (node == null) {
return (-1); // an empty tree has height −1
} 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);
}
}
This solution is even more simpler.
public int getHeight(Node root)
{
if(root!=null)
return 1+ Math.max(getHeight(root.leftchild),getHeight(root.rightchild));
else
return 0;
}
For any given tree, the number of nodes is 1 for the root plus the number of nodes in the left subtree plus the number of nodes in the right subtree :)
Details, like making sure there actually is a left or right subtree, are "left to the reader".
private static int getNumberOfNodes(Node node) {
if (node == null) {
return 0;
}
return 1 + getNumberOfNodes(node.left) + getNumberOfNodes(node.right);
}
public int countNodes(Node root)
{
// Setup
// assign to temps to avoid double call accessors.
Node left = root.getLeft();
Node right = root.getRight();
int count = 1; // count THIS node.
// count subtrees
if (left != null) count += countNodes(left);
if (right != null) count += countNodes(right);
return count;
}
public class Node {
private Node left;
private Node right;
public int size() { return 1+ (left==null?0:left.size())+ (right==null?0:right.size());}
}
int depth(treenode *p)
{
if(p==NULL)return(0);
if(p->left){h1=depth(p->left);}
if(p=>right){h2=depth(p->right);}
return(max(h1,h2)+1);
}
public int numberOfNodes()
{
// This node.
int result = 1;
// Plus all the nodes from the left node.
Node left = getLeft();
if (left != null)
result += left.numberOfNodes();
// Plus all the nodes from the right node.
Node right = getRight();
if (right != null)
result += right.numberOfNodes();
return result;
}
public int getDepthHelper( TreeNode< T > node ) {
int treeHeightLeft;
int treeHeightRight;
//get height of left subtree
if( node.leftNode == null )
treeHeightLeft = 1;
else {
treeHeightLeft = getDepthHelper( node.leftNode) + 1;
}
//get height of right subtree
if( node.rightNode == null )
treeHeightRight = 1;
else {
treeHeightRight = getDepthHelper( node.rightNode) + 1;
}
return Math.max(treeHeightLeft, treeHeightRight);
}