线程“main”java.lang.StackOverflowError中的异常

时间:2014-03-27 05:29:32

标签: java stack-overflow

收到错误:

Exception in thread "main" java.lang.StackOverflowError
    at AVL.insert(AVL.java:45)

我不熟悉我给出的错误,但我知道只有当用于构建AVL树的数组变化很大并且在插入过程中移动到右侧时才会发生这种情况。树。我不知道为什么会发生这种情况(换句话说,我不确切知道StackOverflowError是什么以及为什么会发生这种情况)。

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的类:

//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.");
   }

}

2 个答案:

答案 0 :(得分:1)

由于您的数组从最小到最大排序,当您尝试使用insertPrep插入第15000个节点时(请参阅tree()中的循环),您将以递归方式致电insert(AvlNode node, AvlNode newNode) 15000次。

这是由insert

中的测试引起的
  if (node.key > newNode.key){
     if(node.left!=null){node.left=insert(node.left , newNode);}
     else{node.left=newNode;}
  }

递归太深

递归可能不是你在树中找到位置的最佳选择,你应该求助于一个效率更高的循环,因为你不必在调用之间累积帧。

或者,使用Scala之类的语言知道尾递归,并在编译时自动展开尾递归到循环。

修改 溢出的解释可能过于简单化。见下面的评论

答案 1 :(得分:0)

我认为重新平衡存在问题。

你在做什么

AvlNode result = rebalance(node); 
adjustHeight(result);

这对我来说很奇怪,因为你应该首先调整高度,然后重新平衡然后再调整高度。看起来重新平衡从未发生过,因为高度永远不会更新;因此,你的树会很高;因此,堆栈溢出异常。

我不是100%肯定,但这看起来像是问题。您可以做的一个完整性检查是创建100个节点并检查您的树是否平衡。如果没有,你没有正确实现平衡。