Java “线程中的异常”;“主要”;栈溢出
收到错误:Java “线程中的异常”;“主要”;栈溢出,java,stack-overflow,Java,Stack Overflow,收到错误: Exception in thread "main" java.lang.StackOverflowError at AVL.insert(AVL.java:45) 我不熟悉所给出的错误,但我确实知道,仅当用于构建AVL树的数组大小较大且在插入过程中移动到树的右侧时,才会发生错误。我不知道为什么会发生这种情况(换句话说,我不知道StackOverflowerError到底是什么以及为什么会发生) AVL等级: //AVL.java import java.util.*; i
Exception in thread "main" java.lang.StackOverflowError
at AVL.insert(AVL.java:45)
我不熟悉所给出的错误,但我确实知道,仅当用于构建AVL树的数组大小较大且在插入过程中移动到树的右侧时,才会发生错误。我不知道为什么会发生这种情况(换句话说,我不知道StackOverflowerError到底是什么以及为什么会发生)
AVL等级:
//AVL.java
import java.util.*;
import java.io.*;
public class AVL{
AvlNode root;
public void tree(int[] list){
for(int i=0; i<list.length; i++){
insertPrep(list[i]);
}
}
public void insertPrep(int data){
if (root==null){root = new AvlNode(data);}
else {
AvlNode newNode = new AvlNode(data);
root = insert(root, newNode);
root = rebalance(root);
adjustHeight(root);
}
}
public AvlNode insert(AvlNode node, AvlNode newNode){
if (node.key > newNode.key){
if(node.left!=null){node.left=insert(node.left , newNode);}
else{node.left=newNode;}
}
else if (node.key < newNode.key){
if(node.right!=null){node.right=insert(node.right, newNode);}
else{node.right=newNode;}
}
AvlNode result = rebalance(node);
adjustHeight(result);
return result;
}
public int height (AvlNode node ){
if (node == null){return 0;}
else {return node.height;}
}
public void adjustHeight (AvlNode node){
if (root != null){ root.height = 1+ Math.max(height(root.left),height(root.right));}
}
public AvlNode rebalance (AvlNode node){
AvlNode newAvlNode = node;
if (node.left != null && node.right != null){
if (node.left.height-node.right.height==2){
if (node.left.left.height>node.left.right.height){
AvlNode n2 = node.left;
AvlNode n3 = node;
n3.left = n2.right;
n2.right = n3;
adjustHeight(n3);
adjustHeight(n2);
newAvlNode = n2;
} else {
AvlNode n1 = node.left;
AvlNode n2 = node.left.right;
AvlNode n3 = node;
n1.right = n2.left;
n2.left = n1;
n3.left = n2.right;
n2.right = n3;
adjustHeight(n1);
adjustHeight(n3);
adjustHeight(n2);
newAvlNode = n2;
}
} else if (node.right.height-node.left.height==2){
if (node.right.right.height>node.right.left.height){
AvlNode n1 = node;
AvlNode n2 = node.right;
n1.right = n2.left;
n2.left = n1;
adjustHeight(n1);
adjustHeight(n2);
newAvlNode = n2;
} else {
AvlNode n1 = node;
AvlNode n2 = node.right.left;
AvlNode n3 = node.right;
n1.right = n2.left;
n2.left = n1;
n3.left = n2.right;
n2.right = n3;
adjustHeight(n1);
adjustHeight(n3);
adjustHeight(n2);
newAvlNode = n2;
}
}
}
return newAvlNode;
}
class AvlNode{
int key, height; //data for input numbers and height for height of nodes to keep balance
AvlNode left, right; //left for left side of tree and right for right side of tree
AvlNode(int data){
key = data;
}
}
}
//AVL.java
导入java.util.*;
导入java.io.*;
公共类AVL{
AvlNode根;
公共无效树(int[]列表){
for(int i=0;i newNode.key){
如果(node.left!=null){node.left=insert(node.left,newNode);}
else{node.left=newNode;}
}
else if(node.keynode.left.right.height){
AvlNode n2=node.left;
AvlNode n3=节点;
n3.左=n2.右;
n2.右=n3;
调整高度(n3);
调整高度(n2);
newAvlNode=n2;
}否则{
AvlNode n1=node.left;
AvlNode n2=node.left.right;
AvlNode n3=节点;
n1.右=n2.左;
n2.左=n1;
n3.左=n2.右;
n2.右=n3;
调节高度(n1);
调整高度(n3);
调整高度(n2);
newAvlNode=n2;
}
}else if(node.right.height node.left.height==2){
if(node.right.right.height>node.right.left.height){
AvlNode n1=节点;
AvlNode n2=node.right;
n1.右=n2.左;
n2.左=n1;
调节高度(n1);
调整高度(n2);
newAvlNode=n2;
}否则{
AvlNode n1=节点;
AvlNode n2=node.right.left;
AvlNode n3=node.right;
n1.右=n2.左;
n2.左=n1;
n3.左=n2.右;
n2.右=n3;
调节高度(n1);
调整高度(n3);
调整高度(n2);
newAvlNode=n2;
}
}
}
返回newAvlNode;
}
类AvlNode{
int键,height;//用于输入数字的数据和用于保持平衡的节点高度的高度
AvlNode left,right;//左表示树的左侧,右表示树的右侧
AvlNode(内部数据){
键=数据;
}
}
}
使用AVL初始化:
//Tree.java
import java.io.*;
import java.util.*;
public class Tree{
public static void main(String[] args){
int n = 30000; //numbers to be in arrays
int a[] = new int[n]; //first array
for (int i=0; i<n; i++){
a[i] = i+1; //insert #'s 1-n; smallest to largest
}
//send arrays to be put in AVL trees
AVL avl = new AVL();
double timeSoFar = (double)System.nanoTime();
avl.tree(a);
double treeTime = (double)System.nanoTime() - timeSoFar;
printTime('a',treeTime, "AVL");
}
public static void printTime(char l, double treeTime, String tree){
double treeTimeMin = treeTime/600000;
treeTimeMin/=100000;
System.out.println("Elapsed time for building " + tree + " " + "Tree for array '" + l + "': " + treeTime + " nanoseconds, or: " + treeTimeMin + " minutes.");
}
}
//Tree.java
导入java.io.*;
导入java.util.*;
公共类树{
公共静态void main(字符串[]args){
int n=30000;//数组中的数字
int a[]=新int[n];//第一个数组
对于(int i=0;i由于数组是从最小到最大排序的,因此当您尝试使用insertPrep
插入第15000个节点时(请参见树()中的循环
),您将以递归方式调用插入(AvlNode节点,AvlNode新节点)
15000次
这是由于insert
if (node.key > newNode.key){
if(node.left!=null){node.left=insert(node.left , newNode);}
else{node.left=newNode;}
}
递归太深了
递归可能不是您在树中查找位置的最佳选择,您应该求助于循环,因为您不必在调用之间累积帧,因此循环将更有效
或者,使用Scala之类的语言,它了解尾部递归并在编译时自动将尾部递归展开到循环中
编辑
对溢出的解释可能过于简单化了。请参阅下面的评论。我认为重新平衡有问题
你在干什么
AvlNode result = rebalance(node);
adjustHeight(result);
这对我来说很奇怪,因为你应该先调整高度,然后重新平衡,然后再调整高度。看起来好像从未发生过重新平衡,因为高度从未更新;因此,你的树将非常高;因此,堆栈溢出异常
我不是100%确定,但这看起来像是个问题。你可以做的一个健全性检查是创建,比如说,100个节点,并检查你的树是否平衡。如果不平衡,你就没有正确地实现平衡。堆栈溢出通常意味着递归走得太远。你很可能有一个无限递归。为了确保,增加Java VM堆栈大小e十倍(谷歌会知道这是有标志的),然后看它是否仍然发生。您能确定哪一行是45吗?您是否尝试过使用调试器逐步完成此操作?这似乎是找到答案的最明智的方法。重复的我不认为它将是15000,因为此代码在每次插入后重新平衡树,因此它永远不会遍历多达15000个节点。看看堆栈溢出实际发生在什么时候是很有趣的。你可能是对的:我还没有真正检查过重新平衡的作用。溢出的堆栈和在代码中插入日志记录肯定会有所帮助。然而,使用递归遍历大树的IMHO可能只是从艺术/智力角度来看是不错的int of view:)True。从给出的信息很难知道代码中是否确实存在逻辑错误,或者堆栈是否正被大量的数据淹没