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。从给出的信息很难知道代码中是否确实存在逻辑错误,或者堆栈是否正被大量的数据淹没