Binary Tree and Recursion in Java - java

I have a Node class as follows:
public class Node {
private int value;
private Node leftNode;
private Node rightNode;
public Node(Node leftNode, Node rightNode, int value){
this.leftNode = leftNode;
this.rightNode = rightNode;
this.value = value;
}
//Getter and Setter methods for these variables are defined here
}
This Node class is used to create a Binary tree. I am writing a recursive function in JAVA to calculate the average of all the nodes. The code I have written below does not give correct answer. I think this is because the values of the parameters average and nodeCount are passed, and not the references.
public double treeAverage(Node node, double average, int nodeCount){
nodeCount ++;
if(node == null) return Double.MAX_VALUE;
if(node.getLeftNode()==null && node.getRightNode()==null){
average = ( average + node.getValue() )/nodeCount;
}
if(node.getLeftNode()!=null){
average = treeAverage(node.getLeftNode(), average, nodeCount);
}
if(node.getRightNode()!=null){
average = treeAverage(node.getRightNode(), average, nodeCount);
}
return average;
}
What would be a correct way to right this recursive function in Java? (in C I can pass the references to those parameters). Please correct me if I am wrong.

I guess you could use a helper method. Something like this (I haven't compiled this code, should be taken as hint)
private static long count = 0L;
private static long sum = 0L;
public static int treeAverageHelper(Node node){
if(node == null) return 0;
count ++;
return node.val + treeAverageHelper(node.left) + treeAverageHelper(node.right);
}
public static double treeAvg(Node n){
sum = treeAverageHelper(n);
if (count == 0)
return 0D;
else
return (double)sum/count;
}
The helper, goes through the tree aggregating and counting. And finally you divide the two.

I'm not a fan of these two parts:
if(node == null) return Double.MAX_VALUE;
if(node.getLeftNode()==null && node.getRightNode()==null){
average = ( average + node.getValue() )/nodeCount;
}
For the first statement, why would the average of an empty tree be the highest possible Double? Seems arbitrary. It would be simpler to say it doesn't exist, Double.NaN, or even 0.0 - since the tree has zero elements in it.
For the second statement, you have the logic correct in that if both the children are null, you get back its value. However, you're going to be wrecking your average along the way - if you have twelve nodes, and you're on your third, then your average values will be different when you move to your fourth node.
Move nodeCount to a higher scope, and don't worry about computing the actual average until you've counted the sum of all nodes from the recursive call. Lastly, pass along the total sum of your nodes as you go along.

I think there is a problem in average calculation.
According to your code,
if node have no left child and no right child, you added average + node.getValue() and divide this result by nodeCount.
In fact,
average is total value divided by count.
That means you should get total node value first and divide this by nodeCount.

You need to define a class, such as
class RecursionValues {
int nodeCount;
double average;
}
... and then in your recursive call you pass an instance of this class and modify its fields.

This is how I was able to get it working. Please let me know if it is not a good way.
private double sum = 0;
private int nodeCount = 0;
public double treeAverage(Node node){
if(node == null) return Double.NaN; //Null check
sum = treeSum(node);
double average = (sum/nodeCount);
// before returning, reset the sum and nodeCount, so that same object can use the same function starting with correct/zero values of sum and nodeCount
sum = 0; nodeCount = 0;
return average;
}
public double treeSum(Node node){
nodeCount ++; //update the nodeCount
sum = sum + node.getValue(); //update the sum to include this node
/* If the current node has children, recurse*/
if(node.getLeftNode()!=null){
sum = treeSum(node.getLeftNode());
}
if(node.getRightNode()!=null){
sum = treeSum(node.getRightNode());
}
return sum;
}

Related

Summing binary tree producing unexpected results

Trying to sum all nodes in a BST of Integers
The method is passed 0, but when it transitions from the left sub tree to right sub tree, the sum seems to decrease. Any help would be appreciated
The method is passed the root and a counter initialized to 0
public static int sumTree(TreeNode root,int sum) {
if (root != null) {
System.out.println("current value: " + root.getValue());
sum += (Integer) root.getValue();
System.out.println(sum);
sumTree(root.getLeft(),sum);
sumTree(root.getRight(),sum);
}
return sum;
}
sumTree(root.getLeft(),sum);
sumTree(root.getRight(),sum);
Just looking at these calls in isolation, they don't do anything. Their return values are being lost, and modifications to the recursive copies of sum don't affect the caller's sum; they're different variables.
public static int sumTree(TreeNode root) {
if (root == null) {
return 0;
}
System.out.println("current value: " + root.getValue());
int sum = (Integer) root.getValue();
System.out.println(sum);
sum += sumTree(root.getLeft());
sum += sumTree(root.getRight());
return sum;
}
The fix is to add the return values of the two recursive calls to sum. There's no need to have sum as a parameter: the sum of a sub-tree is independent of the rest of the tree above it.

Recursively finding the average of even numbers in an array

I'm trying to find the average of all even numbers in an array using recursion and I'm stuck.
I realize that n will have to be decremented for each odd number so I divide by the correct value, but I can't wrap my mind around how to do so with recursion.
I don't understand how to keep track of n as I go, considering it will just revert when I return.
Is there a way I'm missing to keep track of n, or am I looking at this the wrong way entirely?
EDIT: I should have specified, I need to use recursion specifically. It's an assignment.
public static int getEvenAverage(int[] A, int i, int n)
{
// first element
if (i == 0)
if (A[i] % 2 == 0)
return A[0];
else
return 0;
// last element
if (i == n - 1)
{
if (A[i] % 2 == 0)
return (A[i] + getEvenAverage(A, i - 1, n)) / n;
else
return (0 + getEvenAverage(A, i - 1, n)) / n;
}
if (A[i] % 2 == 0)
return A[i] + getEvenAverage(A, i - 1, n);
else
return 0 + getEvenAverage(A, i - 1, n);
}
In order to keep track of the number of even numbers you have encountered so far, just pass an extra parameter.
Moreover, you can also pass an extra parameter for the sum of even numbers and when you hit the base case you can return the average, that is, sum of even numbers divided by their count.
One more thing, your code has two base cases for the first as well as last element which is unneeded.
You can either go decrementing n ( start from size of array and go till the first element ), or
You can go incrementing i starting from 0 till you reach size of array, that is, n.
Here, is something I tried.
public static int getEvenAvg(int[] a, int n, int ct, int sum) {
if (n == -1) {
//make sure you handle the case
//when count of even numbers is zero
//otherwise you'll get Runtime Error.
return sum/ct;
}
if (a[n]%2 == 0) {
ct++;
sum+=a[n];
}
return getEvenAvg(a, n - 1, ct, sum);
}
You can call the function like this getEvenAvg(a, size_of_array - 1, 0, 0);
Example
When dealing with recursive operations, it's often useful to start with the terminating conditions. So what are our terminating conditions here?
There are no more elements to process:
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
... okay, now how do we reduce the number of elements to process? We should probably increment index?
index++;
... oh, but only when going to the next level:
getEvenAverage(elements, index++, sum, count);
Well, we're also going to have to add to sum and count, right?
sum += a[index];
count++;
.... except, only if the element is even:
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
... and that's about it:
static int getEvenAverage(int[] elements, int index, int sum, int count) {
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
return getEvenAverage(elements, index + 1, sum, count);
}
... although you likely want a wrapper function to make calling it prettier:
static int getEvenAverage(int[] elements) {
return getEvenAverage(elements, 0, 0, 0);
}
Java is not a good language for this kind of thing but here we go:
public class EvenAverageCalculation {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6,7,8,9,10};
System.out.println(getEvenAverage(array));
}
public static double getEvenAverage(int[] values) {
return getEvenAverage(values, 0, 0);
}
private static double getEvenAverage(int[] values, double currentAverage, int nrEvenValues) {
if (values.length == 0) {
return currentAverage;
}
int head = values[0];
int[] tail = new int[values.length - 1];
System.arraycopy(values, 1, tail, 0, tail.length);
if (head % 2 != 0) {
return getEvenAverage(tail, currentAverage, nrEvenValues);
}
double newAverage = currentAverage * nrEvenValues + head;
nrEvenValues++;
newAverage = newAverage / nrEvenValues;
return getEvenAverage(tail, newAverage, nrEvenValues);
}
}
You pass the current average and the number of even elements so far to each the recursive call. The new average is calculated by multiplying the average again with the number of elements so far, add the new single value and divide it by the new number of elements before passing it to the next recursive call.
The way of recreating new arrays for each recursive call is the part that is not that good with Java. There are other languages that have syntax for splitting head and tail of an array which comes with a much smaller memory footprint as well (each recursive call leads to the creation of a new int-array with n-1 elements). But the way I implemented that is the classical way of functional programming (at least how I learned it in 1994 when I had similar assignments with the programming language Gofer ;-)
Explanation
The difficulties here are that you need to memorize two values:
the amount of even numbers and
the total value accumulated by the even numbers.
And you need to return a final value for an average.
This means that you need to memorize three values at once while only being able to return one element.
Outline
For a clean design you need some kind of container that holds those intermediate results, for example a class like this:
public class Results {
public int totalValueOfEvens;
public int amountOfEvens;
public double getAverage() {
return totalValueOfEvens + 0.0 / amountOfEvens;
}
}
Of course you could also use something like an int[] with two entries.
After that the recursion is very simple. You just need to recursively traverse the array, like:
public void method(int[] values, int index) {
// Abort if last element
if (index == values.length - 1) {
return;
}
method(array, index + 1);
}
And while doing so, update the container with the current values.
Collecting backwards
When collecting backwards you need to store all information in the return value.
As you have multiple things to remember, you should use a container as return type (Results or a 2-entry int[]). Then simply traverse to the end, collect and return.
Here is how it could look like:
public static Results getEvenAverage(int[] values, int curIndex) {
// Traverse to the end
if (curIndex != values.length - 1) {
results = getEvenAverage(values, curIndex + 1);
}
// Update container
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
// Return accumulated results
return results;
}
Collecting forwards
The advantage of this method is that the caller does not need to call results.getAverage() by himself. You store the information in the parameters and thus be able to freely choose the return type.
We get our current value and update the container. Then we call the next element and pass him the current container.
After the last element was called, the information saved in the container is final. We now simply need to end the recursion and return to the first element. When again visiting the first element, it will compute the final output based on the information in the container and return.
public static double getEvenAverage(int[] values, int curIndex, Results results) {
// First element in recursion
if (curIndex == 0) {
// Setup the result container
results = new Results();
}
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
int returnValue = 0;
// Not the last element in recursion
if (curIndex != values.length - 1) {
getEvenAverage(values, curIndex + 1, results);
}
// Return current intermediate average,
// which is the correct result if current element
// is the first of the recursion
return results.getAverage();
}
Usage by end-user
The backward method is used like:
Results results = getEvenAverage(values, 0);
double average results.getAverage();
Whereas the forward method is used like:
double average = getEvenAverage(values, 0, null);
Of course you can hide that from the user using a helper method:
public double computeEvenAverageBackward(int[] values) {
return getEvenAverage(values, 0).getAverage();
}
public double computeEvenAverageForward(int[] values) {
return getEvenAverage(values, 0, null);
}
Then, for the end-user, it is just this call:
double average = computeEvenAverageBackward(values);
Here's another variant, which uses a (moderately) well known recurrence relationship for averages:
avg0 = 0
avgn = avgn-1 + (xn - avgn-1) / n
where avgn refers to the average of n observations, and xn is the nth observation.
This leads to:
/*
* a is the array of values to process
* i is the current index under consideration
* n is a counter which is incremented only if the current value gets used
* avg is the running average
*/
private static double getEvenAverage(int[] a, int i, int n, double avg) {
if (i >= a.length) {
return avg;
}
if (a[i] % 2 == 0) { // only do updates for even values
avg += (a[i] - avg) / n; // calculate delta and update the average
n += 1;
}
return getEvenAverage(a, i + 1, n, avg);
}
which can be invoked using the following front-end method to protect users from needing to know about the parameter initialization:
public static double getEvenAverage(int[] a) {
return getEvenAverage(a, 0, 1, 0.0);
}
And now for a completely different approach.
This one draws on the fact that if you have two averages, avg1 based on n1 observations and avg2 based on n2 observations, you can combine them to produce a pooled average:
avgpooled = (n1 * avg1 + n2 * avg2) / (n1 + n2).
The only issue here is that the recursive function should return two values, the average and the number of observations on which that average is based. In many other languages, that's not a problem. In Java, it requires some hackery in the form of a trivial, albeit slightly annoying, helper class:
// private helper class because Java doesn't allow multiple returns
private static class Pair {
public double avg;
public int n;
public Pair(double avg, int n) {
super();
this.avg = avg;
this.n = n;
}
}
Applying a divide and conquer strategy yields the following recursion:
private static Pair getEvenAverage(int[] a, int first, int last) {
if (first == last) {
if (a[first] % 2 == 0) {
return new Pair(a[first], 1);
}
} else {
int mid = (first + last) / 2;
Pair p1 = getEvenAverage(a, first, mid);
Pair p2 = getEvenAverage(a, mid + 1, last);
int total = p1.n + p2.n;
if (total > 0) {
return new Pair((p1.n * p1.avg + p2.n * p2.avg) / total, total);
}
}
return new Pair(0.0, 0);
}
We can deal with empty arrays, protect the end-user from having to know about the book-keeping arguments, and return just the average by using the following public front-end:
public static double getEvenAverage(int[] a) {
return a.length > 0 ? getEvenAverage(a, 0, a.length - 1).avg : 0.0;
}
This solution has the benefit of O(log n) stack growth for an array of n items, versus O(n) for the various other solutions that have been proposed. As a result, it can deal with much larger arrays without fear of a stack overflow.

Average of each level in a Binary Tree

I am trying to find the average of each level in a binary tree. I am doing BFS. I am trying to do it using a null node. Whenever I find a dummy node, that means I am at the last node at that level. The problem I am facing is that I am not able to add average of the last level in a tree using this. Can Someone Help me?
Consider example [3,9,20,15,7]
I am getting the output as [3.00000,14.50000]. Not getting the average of the last level that is 15 and 7
Here's my code
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> list = new ArrayList<Double>();
double sum = 0.0;
Queue<TreeNode> q = new LinkedList<TreeNode>();
TreeNode temp = new TreeNode(0);
q.offer(root);
q.offer(temp);
int count = 0;
while(!q.isEmpty()){
root = q.poll();
sum += root.val;
if(root != temp)
{
count++;
if(root.left != null){
q.offer(root.left);
}
if(root.right != null){
q.offer(root.right);
}
}
else
{
if(!q.isEmpty()){
list.add(sum / count);
sum = 0;
count = 0;
q.add(temp);
}
}
}
return list;
}
}
Take a look at this code, which executes whenever you find the marker for the end of the current level:
if(!q.isEmpty()){
list.add(sum / count);
sum = 0;
count = 0;
q.add(temp);
}
This if statement seems to be designed to check whether you've finished the last row in the tree, which you could detect by noting that there are no more entries in the queue that would correspond to the next level. In that case, you're correct that you don't want to add the dummy node back into the queue (that would cause an infinite loop), but notice that you're also not computing the average in the row you just finished.
To fix this, you'll want to compute the average of the last row independently of reseeding the queue, like this:
if(!q.isEmpty()){
q.add(temp);
}
list.add(sum / count);
sum = 0;
count = 0;
There's a new edge case to watch out for, and that's what happens if the tree is totally empty. I'll let you figure out how to proceed from here. Good luck!
I would use recursive deep scan of the tree. On each node I would push the value into a map with a pair .
I DID NOT test that code but it should be along the lines.
void scan(int level, TreeNode n, Map<Integer, List<Integer> m) {
List l = m.get(level); if (l==null) {
l = new ArrayList();
m.put(level, l);
}
l.add(n.val);
int nextLevel = level + 1;
if (n.left != null) scan(nextLevel, n.left, m);
if (n.right != null) scan(nextLevel, n.right, m);
}
Once the scan is done I can calculate the average for each level.
for (int lvl in m.keyset()) {
List l = m.get(lvl);
// MathUtils.avg() - it is obvious what it should be
double avg = MathUtils.avg(l);
// you code here
}

Use recursion to count the number of nodes whose value field is between min and max, inclusive, from the "cur" node to the end of the list

My attempt at a solution, I know it is not right because the output for the program is incorrect. What am I doing wrong?
I have an inner node class, each with value fields.This method should return the number of nodes that have value fields between ints min and max.
//---------------- countInRange( Node, int, int ) ------------------
private int countInRange( Node cur, int min, int max )
{
if(cur == null)
return 0;
else {
if(cur.value >= min && cur.value <= max)
return (1+ countInRange(cur.next, min, max));
}
return 1;
}
The problem is that you only do the recursive call if the value is in range, otherwise you pretend that the remainder of the list has only one element in range.
You need to do the recursive call whether the value is in range or not. The only difference is whether you add 1 to the result or not before returning it.
There are three paths through your recursive method:
The node is null, so it cannot be in range nor can it have any children. Returning 0 seems reasonable.
The node is not null, and it is in range. Returning 1 + recursion on the child node looks good.
The node is not null, and it is not in range. Rather than returning 1, I would return 0 + recursion on the child node.
The problem becomes clear if you rewrite and comment the code a bit (this code is functionally equivalent to yours but highlights the problem):
//---------------- countInRange( Node, int, int ) ------------------
private int countInRange( Node cur, int min, int max )
{
if(cur == null) {
// Node is null, end recursion
return 0;
}
if(cur.value >= min && cur.value <= max) {
// Node is in range, recurse and add 1
return (1+ countInRange(cur.next, min, max));
}
} else {
// Node is not in range, recurse
return 1; // ?!
}
}

java binary search tree find closest leaf

Im having trouble with a method that finds the height of the closest leaf. What i have just counts all of the leafs. would i have to separate the recursive calls into two conditional statements to check each one independently? any help or suggestions would be appreciated
this is my method
//find the distance to the closest leaf
public int closeLeaf()
{
int distance;
return distance = closeLeaf(root);
}
private int closeLeaf(StringNode n)
{
int dist = 0;
if(n == null)
{
dist = 0;//empty tree
}
else if(n.getLeft()== null && n.getRight()== null)
{
dist++;
}
else
{
dist =closeLeaf(n.getLeft()) + closeLeaf(n.getRight());
}
return dist;
}
Returning values
Please don't do this:
int distance;
return distance = closeLeaf(root);
Just:
return closeLeaf(root);
On to the real question
Here you're adding up the distance to each leaf:
dist = closeLeaf(n.getLeft()) + closeLeaf(n.getRight());
You probably just want to get the minimum of the two values (to tell you the distance to the closest one).
Instead of
dist =closeLeaf(n.getLeft()) + closeLeaf(n.getRight());
which increments dist for every node encountered, use a static/class member variable that gets incremented each time the closeLeaf function is called.
Limit the recursion to finding a leaf, and the value of dist when you find one will give you the height of the closest leaf.

Categories

Resources