[英]“Exception in thread ”main“ java.lang.StackOverflowError”
[英]Exception in thread “main” java.lang.StackOverflowError
收到錯誤:
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.");
}
}
由於數組是從最小到最大排序的,因此當您嘗試使用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之類的語言了解尾遞歸,並在編譯時自動將尾遞歸展開為循環。
編輯溢出的解釋可能過於簡單。 見下面的評論
我認為重新平衡存在問題。
你在做
AvlNode result = rebalance(node);
adjustHeight(result);
這對我來說很奇怪,因為您應該先調整高度,然后重新平衡,然后再調整高度。 似乎從未發生過重新平衡,因為從未更新過高度。 因此,你的樹會很高。 因此,堆棧溢出異常。
我不是100%肯定的,但是看起來像是問題所在。 您可以做的一項健全性檢查是創建100個節點,並檢查樹是否平衡。 如果沒有,則說明您沒有正確實現平衡。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.