关于java:查找通用树中的下一个更大的节点?

Find the next larger node in the generic tree?

我必须找到并返回通用树中的下一个更大的节点,几乎所有的测试用例都运行正常并给出正确的输出,只有一个测试用例出错了,它可能是任何东西。 我已多次调试我的程序,无法弄清楚可能出现的错误是什么? 实际上我在做什么我正在比较递归为我提取的所有下一个更大的节点并将它们相互比较并最终找到正确的节点? 我被困了一点帮助将不胜感激。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 /* 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;

}


尝试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;
        }
    }

说明:

测试

为了在代码中显示一些错误,我在testForYourCode中提供了一个测试(见下文)。测试返回意外结果。值4的第二个孩子胜出错了。

TreeNode< T >.findNextNode中,我提供了"重构"版本。不确定它是否符合您的要求。两个测试testForModifiedCodetestForModifiedCodeComplex显示refactored版本的行为方式。

通用

而不是编写只能处理TreeNode的函数,我决定编写一个适用于所有类型的泛型函数。

对照

实际比较被委托给Comparator对象。必须将Comparator的实例传递给findNextNode方法。这可以使用Java 8 lambda语法即时完成,例如(a,b)->{return b-a;}。这为实现增加了一些灵活性。通过更改比较器,您还可以使用(a,b)->{return a-b;}搜索"下一个较小节点"。

它能做什么

如果入口节点满足Comparator.compare实现定义的条件,则算法将停止。否则,从第一个子节点开始执行深度搜索(等等)。一旦节点与比较标准匹配,算法就会停止。如果没有节点匹配,则返回null。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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;
        }
    }


}

最后,我在代码中发现了这个错误。它位于以下部分。

1
2
3
4
5
6
7
8
9
10
if(next!=null)
{
    if(root.data>n && root.data<next.data)
    return root;
    else
    return next;

}
else
return null;

假设如果next == null那么else将被执行,这将返回null。这是错误的,因为root也可能是下一个更大的节点,因此我也必须检查该条件

正确的版本是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
    }


我看到一个极端测试可能会失败:如果正确答案是一个具有数据Integer.MAX_VALUE的节点,那么您的代码将返回null而不是该节点。

对代码进行最少更改的解决方案是替换:

1
count[i].data<nextLarger

有:

1
count[i].data<=nextLarger

这样,即使count[i].dataInteger.MAX_VALUE,也一定要给next一个非空值。

注意:如果要将两个for循环连接成一个,则不需要使用count数组,而只需要使用单个节点变量。


TreeNode通常看起来像这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
    }
}