Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在二叉树中查找值以避免堆栈溢出异常_Java_Algorithm_Recursion - Fatal编程技术网

Java 在二叉树中查找值以避免堆栈溢出异常

Java 在二叉树中查找值以避免堆栈溢出异常,java,algorithm,recursion,Java,Algorithm,Recursion,我试图在二叉树中找到一个值,并返回具有我要查找的值的节点 我做了一个算法,当值不在树的很深层次时,该算法工作得很好,但当值位于树的较深位置时,我得到一个java.lang.StackOverflowerError。这是我的密码: class Node { // keep these​​​​​​​​‌‌‌‌‌​​‌‌​​​​​​‌​‌​‌‌‌​ fields Node left, right; int value; public Node find(int v)

我试图在二叉树中找到一个值,并返回具有我要查找的值的节点

我做了一个算法,当值不在树的很深层次时,该算法工作得很好,但当值位于树的较深位置时,我得到一个
java.lang.StackOverflowerError
。这是我的密码:

class Node {

    // keep these​​​​​​​​‌‌‌‌‌​​‌‌​​​​​​‌​‌​‌‌‌​ fields
    Node left, right;
    int value;

    public Node find(int v){
        if(v > this.value && this.right != null)
            return right.find(v);
        if(v < this.value && this.left != null)
            return left.find(v);
        if(this.value == v)
            return this;
        return null;
    }
}
类节点{
//留着这些​​​​​​​​‌‌‌‌‌​​‌‌​​​​​​‌​‌​‌‌‌​ 领域
左、右淋巴结;
int值;
公共节点查找(int v){
如果(v>this.value&&this.right!=null)
返回权。查找(v);
如果(v

有人能给我一个关于这个问题的解决方案吗(我听说过一些类似尾部优化递归的东西),但我不确定它是否能在Java中工作。

您可以使用
Xss
JVM参数来增加分配给线程堆栈的内存。这将允许您拥有更大的方法调用堆栈

-Xsssize

设置线程堆栈大小(以字节为单位)。附加字母k或k表示KB,m或m表示MB,g或g表示GB。这个 默认值取决于虚拟内存

以下示例将线程堆栈大小设置为1024 KB 不同单位:

-Xss1m

-Xss1024k

-Xss1048576

参考:

否则,您总是可以将递归转换为a循环,这意味着您必须自己在堆栈中管理方法的调用堆栈(参数和返回值),这可能会变得混乱


注意:对于搜索操作,不需要Jon Skeet提到的堆栈。搜索不需要跟踪它的位置。但是,对于回溯,需要引用父级,并且我们必须确保始终从左子级开始。

您的代码重铸为迭代的示例:

class Node {

    // keep these​​​​​​​​‌‌‌‌‌​​‌‌​​​​​​‌​‌​‌‌‌​ fields
    Node left, right;
    int value;

    public Node find(int v){
        Node n = this;

        while (n != null)
        {
            if (v > n.value)
                n = n.right;
            else if (v < n.value)
                n = n.left;
            else // v == n.value
                return n;
        }

        return null;
    }
}
类节点{
//留着这些​​​​​​​​‌‌‌‌‌​​‌‌​​​​​​‌​‌​‌‌‌​ 领域
左、右淋巴结;
int值;
公共节点查找(int v){
节点n=这个;
while(n!=null)
{
如果(v>n.value)
n=n.对;
否则如果(v
编辑:只是一个关于如何工作的注释,以防不清楚。由于您不需要记住关于如何到达当前节点的任何信息,因此我们只跟踪需要搜索的当前子树的根。在每一步中,我们要么确定没有剩下的子树可供搜索(第一个条件),要么在左边或右边有一个子树(中间两个条件),要么在当前子树的根处实际找到了值(最后一个条件)。我们一直在寻找,直到我们用完了子树(whilecondition),如果我们用完了,我们知道值不在树中,我们返回null


编辑:正如评论中所指出的,如果
s,则使用连续的
s是一个问题。我已经更新了使用if/else if/else的代码。

最简单的方法是将其转换为
while
循环,它只维护“我们正在测试的当前节点”的状态

在循环的每次迭代中,有三种可能性:

  • 当前节点具有正确的值,在这种情况下,可以返回该值
  • 当前节点在正确的“侧”上有一个子节点,在这种情况下,您可以将该子节点作为新的“当前节点”继续迭代
  • 以上两种情况都不是,在这种情况下,找不到值,您可以返回null
比如:

public Node find(int v) {
    Node current = this;
    while (current != null) {
        if (current.value == v) {
            return current;
        }
        // This will drop out of the loop naturally if there's no appropriate subnode
        current = v < current.value ? current.left : current.right;
    }
    return null;
}
公共节点查找(int v){
节点电流=此;
while(当前!=null){
如果(当前值==v){
回流;
}
//如果没有合适的子节点,这将自然退出循环
电流=v
或者代码更少,但可读性可能更低:

public Node find(int v) {
    Node current = this;
    // Keep navigating down the tree until either we've run
    // out of nodes to look at, or we've found the right value.
    while (current != null && current.value != v) {
        current = v < current.value ? current.left : current.right;
    }
    return current;
}
公共节点查找(int v){
节点电流=此;
//继续沿着树导航,直到我们跑完为止
//没有要查看的节点,或者我们找到了正确的值。
while(current!=null&¤t.value!=v){
电流=v
树搜索用于避免在大型数组上迭代

树方法的缺点是当节点值排序时。加载树时,每个节点都向左或向右移动,导致大量递归。话虽如此,堆栈溢出需要大量递归

您可以散列这些值,这将有助于平衡树,或者可以增强树构建算法,以便在特定分支过长时平衡树


话虽如此,您还应该查看树中有多少节点足以导致堆栈溢出。您的代码中可能存在此处未显示的错误。

提示:避免深层递归的方法通常是使用迭代。你怎么能把你的方法变成一个循环呢?把你的二叉树以数组的形式存储起来,比如第i个位置,它的左、右子元素是2*i和2*i+1,然后你可以很容易地迭代这个数组……所以当你从用户那里获取输入时,对于数组中的二叉树以及出于动态目的,您可能必须使用数组list@JonSkeet哇,很高兴见到上帝site@zenwraight,
2*i
2*i+1
索引仅对完整的二叉树(例如二进制堆)有效,但确保这不会取消在数组中存储二叉树的功能