简体   繁体   中英

Find the next larger node in the generic tree?

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;

}

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.

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;
    }

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 testForModifiedCode and 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, eg (a,b)->{return ba;} . This adds some flexibility to the implementation. By changing the comparator you can also search for the 'next lesser node' using (a,b)->{return ab;} .

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;
        }
    }


}

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;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM