0

I have to find and return the next larger node in the generic tree almost all testcases are running fine and giving correct output just one testcase is coming out wrong and it could be anything. I have debugged my program many times and could not figured out what bug that could be? Actually what I'm doing I'm comparing all the next larger nodes that recursion has fetched for me and comparing them with one another and ultimately find the right one? I'm stuck a little help would be appreciated.

Code

 /* TreeNode structure 
    class TreeNode<T> {
    T data;
    ArrayList<TreeNode<T>> children;

    TreeNode(T data){
        this.data = data;
        children = new ArrayList<TreeNode<T>>();
    }
}*/




public static TreeNode<Integer> findNextLargerNode(TreeNode<Integer> root, int n){

    if(root==null)
    return root;

    if(root.children.size()==0)
    {
        if(root.data>n)
        {
            return root;
        }

        else
        return null;

    }

    TreeNode<Integer> count[] = new TreeNode[root.children.size()];

    for(int i=0;i<root.children.size();i++)
    {
        count[i] = findNextLargerNode(root.children.get(i),n);
    }

    int nextLarger=Integer.MAX_VALUE;
    TreeNode<Integer> next = null;


    for(int i=0;i<count.length;i++)
    {
        if(count[i]!=null)
        {
            if(count[i].data>n && count[i].data<nextLarger)
            {
                nextLarger = count[i].data;
                next = count[i];
            }
        }
    }

    if(next!=null)
    {


        if(root.data>n && root.data<next.data)
        return root;
        else
        return next;

    }
    else 
    return null;

}
  • Since this is a tree I suggest you use the tree structure to find the next element instead of using Iteration. If you are wondering how to do this I suggest you read an example which works like the source for TreeMap or something else on line. Hint: don't use size(), arrays, iteration. Hint2: if you are going to call size(), don't call it more than once. – Peter Lawrey Apr 04 '17 at 14:36
  • Normally a Tree has a left and a right node. In the manner it is used, it looks like a complex array structure, though it is not clear why it is so complex. – Peter Lawrey Apr 04 '17 at 14:40
  • @PeterLawrey It is a generic tree. A node in this tree could have more than just two children. I have added the `treeStructure` in EDIT – Prince Vijay Pratap Apr 04 '17 at 14:43
  • So is there any relationship between these `children` and the `data`? Why have a tree at all, you could put every element in the children collection? It appears you have generalised it to something which is not a tree, but a complex array list. – Peter Lawrey Apr 04 '17 at 14:48
  • I have used a `arraylist` to store the reference to its all children . – Prince Vijay Pratap Apr 04 '17 at 14:50
  • That is my complaint, and the reason this is not a tree, so you have to explain what you are doing with those children and whether there is any relationship to the data in the node. – Peter Lawrey Apr 04 '17 at 14:54
  • 1
    Please define 'next'. Your code searches for value >n. Since your tree is not ordered (right?), it seems possible to have many 'larger nodes' in the same distance to your starting point. Looking at your code it seems that the last child `next`should win the race. But than `if(root.data>n && root.data – jschnasse Apr 04 '17 at 15:19
  • @jschnasse the reason I have wrote this `if(root.data>n && root.data – Prince Vijay Pratap Apr 04 '17 at 15:32
  • Are the children sorted from low to high data? Could it be that the test fails because your code takes too long to return the answer? – trincot Apr 04 '17 at 20:35
  • @trincot If it would take too long to return then it will show TLE(time limit exceeded) error. I don't think that would be the case as other testcases ran pretty fast – Prince Vijay Pratap Apr 04 '17 at 20:43
  • What about my first question? – trincot Apr 04 '17 at 20:53
  • @trincot no they are not sir – Prince Vijay Pratap Apr 04 '17 at 20:55
  • @PrinceVijayPratap I added a comprehensive answer. Please give it a try. I'm happy to get some questions about it. – jschnasse Apr 05 '17 at 15:08

4 Answers4

1

I see one extreme test which could fail: if the correct answer is a node that has as data Integer.MAX_VALUE, then your code will return null instead of that node.

A solution with the least change to your code, is to replace:

count[i].data<nextLarger

with:

count[i].data<=nextLarger

This way you are sure to give next a non-null value even if count[i].data is Integer.MAX_VALUE.

NB: If you would join both for loops into one, you would not need to use a count array, but just a single node variable.

trincot
  • 317,000
  • 35
  • 244
  • 286
1

Finally, I have found the bug in my code. It lies in the following segment.

if(next!=null)
{
    if(root.data>n && root.data<next.data)
    return root;
    else
    return next;

}
else 
return null;

Suppose if next == null then else will get executed which will return the null. This is wrong because root can also be the next larger node so I have to check for that condition also

The correct version is :

if(next!=null)
    {
        if(root.data>n && root.data<next.data)
        return root;
        else
        return next;

    }
    else 
    {
        if(root.data>n)
        return root;
        else 
        return null;
    }
  • 1
    Good job you spotted it! – trincot Apr 05 '17 at 05:55
  • Your code still contains bugs. Look at the example of tree with `root=0` and `children = {5,4,5}` . Your algorithm will identify the `4` node as 'next larger child' which seems to be wrong. I provided a testcase for this example in my answer. – jschnasse Apr 07 '17 at 06:35
1

Try

public class Test {

    class TreeNode<T> {
        T data;
        List<TreeNode<T>> children;

        TreeNode(T data) {
            this.data = data;
            children = new ArrayList<TreeNode<T>>();
        }
        public  TreeNode<T> findNextNode(T n,Comparator<T> comp) {
            if (comp.compare(data , n) < 0) {
                return this;
            }
            if (children.size() == 0) {
                return null;
            }
            for (int i = 0; i < children.size(); i++) {
                TreeNode<T> node= children.get(i).findNextNode(n,comp);
                if(node!=null)return node;
            }
            return null;
        }
    }

Explanation:

Tests

To show some errors in your code I provide a test in testForYourCode (see below). The test returns an unexpected result. The second child with a value of 4 wins which is wrong.

In TreeNode<T>.findNextNode I provide a 'refactored' version. Not sure if it does what you have asked for. The two tests testForModifiedCodeand testForModifiedCodeComplex show how the refactored version behaves.

Generic

Instead of writing a function that can deal only with TreeNode<Integer> I decided to write a generic function that works on all kind of types.

Comparison

The actual comparison is delegated to a Comparator object. An instance of a Comparator must be passed to the findNextNode method. This can be done on-the-fly using Java 8 lambda syntax, e.g. (a,b)->{return b-a;}. This adds some flexibility to the implementation. By changing the comparator you can also search for the 'next lesser node' using (a,b)->{return a-b;}.

What it does

If the entry node fulfills the criteria defined by the Comparator.compare implementation the algorithm stops. Otherwise a deep search is performed starting at the first child node (and so forth). As soon as the node matches the comparison criteria the algorithm stops. If no node matches, null is returned.

package stack43210199;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import org.junit.Assert;

public class Test {

    class TreeNode<T> {
        T data;
        List<TreeNode<T>> children;

        TreeNode(T data) {
            this.data = data;
            children = new ArrayList<TreeNode<T>>();
        }
        public  TreeNode<T> findNextNode(T n,Comparator<T> comp) {
            if (comp.compare(data , n) < 0) {
                return this;
            }
            if (children.size() == 0) {
                return null;
            }
            for (int i = 0; i < children.size(); i++) {
                TreeNode<T> node= children.get(i).findNextNode(n,comp);
                if(node!=null)return node;
            }
            return null;
        }
    }

    @org.junit.Test
    public void testForYourCode() {
        TreeNode<Integer> root = buildNode(0);
        TreeNode<Integer> firstChild = buildNode(5);
        TreeNode<Integer> secondChild = buildNode(4);
        TreeNode<Integer> thirdChild = buildNode(5);
        root.children.add(firstChild);
        root.children.add(secondChild);
        root.children.add(thirdChild);
        //Arrg - not as expected
        Assert.assertEquals(secondChild, findNextLargerNode(root, 0));
    }

    @org.junit.Test
    public void testForModifiedCode() {
        TreeNode<Integer> root = buildNode(2);
        TreeNode<Integer> firstChild = buildNode(5);
        TreeNode<Integer> secondChild = buildNode(4);
        TreeNode<Integer> thirdChild = buildNode(5);
        TreeNode<Integer> fourthChild = buildNode(1);
        root.children.add(firstChild);
        root.children.add(secondChild);
        root.children.add(thirdChild);
        thirdChild.children.add(fourthChild);
        //find next greater
        Assert.assertEquals(firstChild, root.findNextNode(2,(a,b)->{return b-a;}));
        //find next lesser
        Assert.assertEquals(fourthChild, root.findNextNode(2,(a,b)->{return a-b;}));
        }

    @org.junit.Test
    public void testForModifiedCodeComplex() {
        TreeNode<Integer> root = buildNode(2);
        TreeNode<Integer> firstChild = buildNode(2);
        TreeNode<Integer> secondChild = buildNode(4);
        TreeNode<Integer> thirdChild = buildNode(5);
        TreeNode<Integer> fourthChild = buildNode(1);
        TreeNode<Integer> sixthChild = buildNode(8);
        firstChild.children.add(fourthChild);
        firstChild.children.add(sixthChild);
        root.children.add(firstChild);
        root.children.add(secondChild);
        root.children.add(thirdChild);
        //find next greater
        Assert.assertEquals(sixthChild, root.findNextNode(2,(a,b)->{return b-a;}));
        //find next lesser
        Assert.assertEquals(fourthChild, root.findNextNode(2,(a,b)->{return a-b;}));
    }

    private TreeNode<Integer> buildNode(int i) {
        return new TreeNode<Integer>(new Integer(i));
    }

    public static TreeNode<Integer> findNextLargerNode(TreeNode<Integer> root, int n) {

        if (root == null)
            return root;

        if (root.children.size() == 0) {

            if (root.data > n) {
                return root;
            }

            else
                return null;

        }

        TreeNode<Integer> count[] = new TreeNode[root.children.size()];

        for (int i = 0; i < root.children.size(); i++) {
            count[i] = findNextLargerNode(root.children.get(i), n);
        }

        int nextLarger = Integer.MAX_VALUE;
        TreeNode<Integer> next = null;

        for (int i = 0; i < count.length; i++) {
            if (count[i] != null) {
                if (count[i].data > n && count[i].data < nextLarger) {
                    nextLarger = count[i].data;
                    next = count[i];
                }
            }
        }

        if (next != null) {
            if (root.data > n && root.data < next.data)
                return root;
            else
                return next;

        } else {
            if (root.data > n)
                return root;
            else
                return null;
        }
    }


}
Community
  • 1
  • 1
jschnasse
  • 8,526
  • 6
  • 32
  • 72
0

A TreeNode would normally look like this.

class TreeNode<T extends Comparable<T>> {
    T data;
    TreeNode<T> left, right;

    TreeNode(T data){
        this.data = data;
    }

    public TreeNode<T> findNextLargerNode(T t) {
        if (data.compareTo(t) <= 0)
            return right == null ? null : right.findNextLargerNode(t);
        T found = left == null ? null : left.findNextLargerNode(t);
        return found == null ? this : found;
    }
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • sir the tree which I have mentioned is a GENERIC – Prince Vijay Pratap Apr 04 '17 at 14:48
  • @PrinceVijayPratap the is called a generic, adding a list in a tree is not a tree any more. – Peter Lawrey Apr 04 '17 at 14:52
  • sir I think i have confused you between general term `generic` and the `java term generic` . My problem is I have a tree which could have more than just two or one children. So in order to store the reference of the children I have used arrayList. – Prince Vijay Pratap Apr 04 '17 at 14:57
  • @PrinceVijayPratap trees can have any number of nodes in them already, but they have at most two directly under each node, one to the left holding all those less than the data value and one to the right holding all those greater than the data value. You need to be able to clearly say *why* you are using a list, or you will cause more confusion, to yourself and others. – Peter Lawrey Apr 04 '17 at 15:05
  • @PrinceVijayPratap If you use the term generic to mean it's not really a tree, that doesn't say what it is, just what it is not. – Peter Lawrey Apr 04 '17 at 15:07
  • Sir I think you are talking about binary search trees , ok lets say I have a datastructure which looks like a tree but here a node can have more than two children so how I am supposed to store all the references to their children. I should be using something like `arrayList` ? shouldn't I? – Prince Vijay Pratap Apr 04 '17 at 15:13
  • I got that, but the question I keep asking is; does it have anything to do with a tree structure and if it does, does `data` have anything to do with the children. Is there any reason you would need more than one arraylist as you can use this to store every element. – Peter Lawrey Apr 04 '17 at 15:21
  • The diagram is so generic it's isn't useful for anything I can think of. i.e. it wouldn't make sense to try and implement something without more details. The only thing you can say about a generic tree is that it's not a graph. – Peter Lawrey Apr 04 '17 at 15:27
  • @PeterLawrey : Really - you can't think of a reason to use a tree with more than two children? For example: modelling a filesystem? – gilleain Apr 04 '17 at 17:06
  • @gilleain a file system which has data at each node and the children don't have names... No I don't see the point. – Peter Lawrey Apr 04 '17 at 17:56