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
索引仅对完整的二叉树(例如二进制堆)有效,但确保这不会取消在数组中存储二叉树的功能