查找树高时的stackoverflow

时间:2018-05-07 02:28:04

标签: java algorithm recursion data-structures tree

我正在编写一个简单的函数来查找节点的高度,当树有50个节点(一个AVL树,平衡)时,该节点的工作正常。但是一旦树长到一定大小,我就得到{{1跟踪行Exception in thread "main" java.lang.StackOverflowError& rSHeight = this.right.height()+1;,我认为这是因为我对递归的破旧实现,

lSHeight = this.left.height()+1;

我想知道在树拥有超过1000个节点之前,是否有人可以想到如何避免public int height() { int lSHeight,rSHeight; if (this.left != null) { lSHeight = this.left.height()+1; } else { lSHeight = 0; } if (this.right != null) { rSHeight = this.right.height()+1; }else { rSHeight = 0; } if (lSHeight ==0 && rSHeight ==0) { return 0; } else { int ret = Math.max(lSHeight, rSHeight); return ret; } } ? (不假设高度变量,因为此函数适用于实际stackoverflowerror派生的BaseNode类 感谢大家阅读我的帖子,正如所建议的,这是我的实现,基本的想法是让AVLnode实现树的最基本功能,这样我就可以实现我刚学习的其他树类型。 BaseNode是我当前正在研究的那个,以AVLnode开头的方法是我为检查功能而编写的所有测试,

trial

这是public abstract class BaseNode <T extends BaseNode<T>>{ int val; T parent; T left; T right; public boolean insert(T tender) { if ((tender.val < this.val) && (this.left != null)){ return this.left.insert(tender); } else if ((tender.val < this.val)&& (this.left == null)){ this.left = tender; tender.parent = (T) this; // host instance will be the exact type, no real cast involved return true; } else if((tender.val>this.val)&&(this.right!=null)) { return this.right.insert(tender); } else if ((tender.val>this.val)&&(this.right == null)) { this.right = tender; tender.parent = (T) this; return true; } else { return false; } } public BaseNode<?> min(){ if (this.left != null) { return this.left.min(); } else { return this; } } public BaseNode<?> successor(){ if (this.right != null) { return this.right.min(); } else { boolean spot = true; BaseNode tempt = this; while(spot) { if (tempt.parent == null) { return null; } else if (tempt == tempt.parent.left) { spot = false; return tempt.parent; } else { tempt = tempt.parent; } } } return null; } public BaseNode<?> search(int key){ if ((key < this.val) && (this.left != null)){ return this.left.search(key); } else if ((key < this.val)&& (this.left == null)){ return null; } else if((key>this.val)&&(this.right!=null)) { return this.right.search(key); } else if ((key>this.val)&&(this.right == null)) { return null; } else { return this; } } //replace the host node with jim in the Tree //certainly not a good practice to just change the value public void swapIn(BaseNode jim) { //the connections on New Node side are done here //the connections on other Nodes side are done in 'adopt' jim.parent = this.parent; if(this.left != jim) { jim.left = this.left; } if (this.right!=jim) { jim.right=this.right; } this.adopt(jim); } public void adopt(BaseNode stepK) { if(this.parent!=null) { if (this == this.parent.left) { this.parent.left = (T) stepK; } else { this.parent.right = (T) stepK; } } if(this.left != stepK && this.left != null) { this.left.parent = (T) stepK; } if (this.right!= stepK && this.right!=null) { this.right.parent = (T) stepK; } } public boolean delete(int key) { BaseNode sp = this.search(key); if (sp==null) { return false; }else { if ((sp.left==null)&&(sp.right==null)) { sp.swapIn(null); } else if((sp.left==null)^(sp.right==null)) { if (sp.left==null) { sp.swapIn(sp.right); } else { sp.swapIn(sp.left); } } else { BaseNode hinch =sp.successor(); //it's not possible to have hinch== null here if(hinch.right!=null) { hinch.swapIn(hinch.right); } sp.swapIn(hinch); //sp.findRoot().delete(hinch.val); } return true; } } //A recursive algorithm the returns height public int height() { int lSHeight,rSHeight; if (this.left != null) { lSHeight = this.left.height()+1; } else { lSHeight = 0; } if (this.right != null) { rSHeight = this.right.height()+1; }else { rSHeight = 0; } if (lSHeight ==0 && rSHeight ==0) { return 0; } else { int ret = Math.max(lSHeight, rSHeight); return ret; } } //Recursively put tree rooted at hose instance into array 'rack' as a heap public void stashBST(T rack[],int idx){ //rack was created as subclass array, the host is also a subclass object, proper cast rack[idx] = (T) this; if(this.left!=null) { this.left.stashBST(rack, idx*2+1); } if (this.right != null) { this.right.stashBST(rack, idx*2+2); } } //return val of host as a string object with 'toklen' length public String printableNode(int tokLen) { String signi = Integer.toString(this.val); try { if (signi.length()<= tokLen) { int gap = tokLen - signi.length(); int front = gap/2; int back = gap - front; String pre =""; String post= ""; for(int i =0;i< front;i++) { pre = pre+ " "; } for(int i =0;i< back;i++) { post = post+ " "; } String ret = pre+signi+post; return ret; } else { throw new RuntimeException("the number is too big!"); } } catch (RuntimeException e) { return null; } } public BaseNode findRoot() { if(this.parent!=null) { return this.parent.findRoot(); } else { return this; } } public boolean fost(T nbie) { if (this.parent != null){ if (this == this.parent.left) { this.parent.left = nbie; nbie.parent = this.parent; } else { this.parent.right = nbie; nbie.parent = this.parent; } return true; } else { nbie.parent = null; return false; } } public boolean leftRot() { if(this.right == null) { return false; } else { this.fost(this.right); this.parent = this.right; T tempD = this.right.left; this.right.left = (T) this; this.right = tempD; return true; } } public boolean rightRot() { if(this.left == null) { return false; } else { this.fost(this.left); this.parent = this.left; T tempD = this.left.right; this.left.right = (T) this; this.left = tempD; return true; } } //print a tree rooted at host public void printTree() { int height = this.height(); //Hvae Array of BaseNode doesn't hurt, it's just reference, we can cast it back if needed BaseNode rack[]=new BaseNode[(int) Math.pow(2, height+1)]; this.stashBST((T[]) rack, 0); int TokCap = (int)Math.pow(2, height); int maxWidth = TokCap*5; for (int i=0;i<height+1;i++) { int numLv =(int) Math.pow(2, i); int widthLv = maxWidth/numLv; for(int j =(int)Math.pow(2, i)-1; j<(int)Math.pow(2, i+1)-1;j++) { if(rack[j]!= null) { if (rack[j].val==1){ int begal = 15; } System.out.print(rack[j].printableNode(widthLv)); } else { String temp = ""; for(int k=0;k<widthLv;k++) { temp = temp+" "; } System.out.print(temp); } } System.out.println(""); } } } 类:

Tree

这是public class tree <T extends BaseNode> { T root; public tree(T adam) { if (adam != null) { root = adam; } } public void reCal() { while(root.parent != null) { root = (T) root.parent; } } public void showTree() { root.printTree(); } public boolean insert(T nbie) { if (this.root != null){ boolean res = this.root.insert(nbie); //this.reCal(); if (root instanceof AVLnode) { ((AVLnode) nbie).fixProp(); } this.reCal(); return res; } else { //if empty tree, assume the we having a plain root = nbie; return true; } } public boolean delete(int key) { if (root.val == key) { if (root.right != null) { T temp = (T) root.successor(); root.delete(key); this.root = temp; return true; } else { root.swapIn(root.left); this.root = (T) root.left; return true; } } else { return root.delete(key); } } public T search(int key) { if(root == null) { return null; } else { return (T) root.search(key); } } } import java.util.Arrays; 类:

AVLnode

这是public class AVLnode extends BaseNode<AVLnode>{ public int hMark; public AVLnode(int key) { this.val = key; this.left = null; this.right = null; this.parent = null; this.hMark = 0; } public boolean insert(AVLnode nbie) { boolean result = super.insert(nbie); if (result == true) { if (((this.left == nbie) && (this.right ==null))||((this.right == nbie)&&(this.left==null))) { this.hMark = this.hMark + 1; } } else { return result; } if (this.left == null) { this.hMark = this.right.hMark +1; } else if (this.right == null) { this.hMark = this.left.hMark + 1; } else { this.hMark = Math.max(this.left.hMark,this.right.hMark)+1; } return result; } public void fixProp() { int lh, rh; if(this.left == null) { lh = -1; } else { lh = this.left.hMark; } if (this.right == null) { rh=-1; } else { rh = this.right.hMark; } if(Math.abs(lh-rh) >1 ) { int llh,lrh,rrh,rlh; if (this.left!=null) { if (this.left.left == null) { llh = -1; } else { llh = this.left.left.hMark; } if(this.left.right == null) { lrh = -1; } else { lrh = this.left.right.hMark; } } else { llh = -1; lrh = -1; } if(this.right !=null ) { if(this.right.left == null) { rlh = -1; } else { rlh = this.right.left.hMark; } if(this.right.right == null) { rrh = -1; } else { rrh = this.right.right.hMark; } } else { rlh = -1; rrh = -1; } if((lh>rh) && (llh>lrh)){ this.rightRot(); if(this.parent.parent != null) { this.parent.parent.fixProp(); } else { return; } } else if ((rh>lh)&&(rrh>rlh)) { this.leftRot(); if(this.parent.parent != null) { this.parent.parent.fixProp(); } else { return; } } else if ((lh>rh)&&(lrh>llh)) { this.left.leftRot(); this.rightRot(); if(this.parent.parent != null) { this.parent.parent.fixProp(); } else { return; } } else if((rh>lh)&&(rlh>rrh)) { this.right.rightRot(); this.leftRot(); if(this.parent.parent != null) { this.parent.parent.fixProp(); } else { return; } } } else { if(this.parent != null) { this.parent.fixProp(); } else { return; } } } public boolean heightFeatureCheck() { if (this.hMark == this.height()) { boolean lOut = true; boolean rOut = true; if (this.left!=null) { lOut = this.left.heightFeatureCheck(); } if (this.right != null) { rOut = this.right.heightFeatureCheck(); } return (lOut && rOut); } else { return false; } } public static void trialInsertionAVL() { // for testing convenience, not gonna have a tree int statRack [] = new int [] {45,48,35,40,30,8}; AVLnode adam = new AVLnode(statRack[0]); for(int i =1;i<statRack.length;i++) { AVLnode bitco = new AVLnode(statRack[i]); adam.insert(bitco); } adam.printTree(); System.out.println("===================================================="); //System.out.print(adam.heightFeatureCheck()); AVLnode chris = (AVLnode) adam.search(8); AVLnode futKing = (AVLnode) adam.search(35); chris.fixProp(); futKing.printTree(); } public static void trialAVLTree() { int pool [] = new int [] {15, 42, 12, 29, 29, 44, 38, 29, 29, 33, 0,}; AVLnode adam = new AVLnode(pool[0]); tree oak = new tree(adam); for(int i=1;i<pool.length;i++) { AVLnode son = new AVLnode(pool[i]); oak.insert(son); oak.showTree(); System.out.println("++++++++++++++++++++++++++++++++++++++"); } oak.showTree(); } public static void trialDynamicAVL() { int pool [] = Node.rawGene(); //System.out.println(Arrays.toString(pool)); AVLnode adam = new AVLnode(pool[0]); tree oak = new tree(adam); for(int i=1;i<pool.length;i++) { AVLnode son = new AVLnode(pool[i]); oak.insert(son); oak.showTree(); System.out.println("++++++++++++++++"+Integer.valueOf(i)+"++++++++++++++++++++++"); } oak.showTree(); System.out.println("this is it!!!!!!"); } public static void main(String args[]) { trialDynamicAVL(); } }

Node

另外,正如您可能已经注意到的那样,我花了大量代码来检查某些东西是否为空,我想知道是否有更好的方法可以做到这一点?我读过的一个解决方案是为所有节点的import java.util.Arrays; import java.util.Random; import java.math.*; public class Node extends BaseNode<Node>{ public Node(int key) { this.val = key; this.parent = null; this.left = null; this.right =null; } public static int[] rawGene() { int drizzy [] = new int [100]; Random magic = new Random(); for (int i=0;i<100;i++) { drizzy[i] = magic.nextInt(50); } System.out.println(Arrays.toString(drizzy)); return drizzy; } public int bfsTrial(int counted) { counted++; System.out.println(this.val); if(this.left != null) { counted = this.left.bfsTrial(counted); } if (this.right != null) { counted = this.right.bfsTrial(counted); } if ((this.left==null) && (this.right == null)) { return counted; } return counted; } public void bstInArray(Node yard [], int r_idx) { //the adam is the node we just discover, r_idx is the idx of the adam yard[r_idx] = this; if (this.left != null){ this.left.bstInArray( yard, r_idx*2); } if(this.right != null) { this.right.bstInArray(yard, (r_idx*2+1)); } if((this.left == null)&&(this.right==null)) { return; } } public static Node makeTree(int pool []) { Node root = new Node(pool[0]); for(int i =1;i<pool.length;i++) { Node bitco = new Node(pool[i]); root.insert(bitco); } return root; } public static Node makeTree() { int statRack [] = new int [] {45, 14, 5, 47, 20, 9, 4, 37, 30, 1}; return makeTree(statRack); } //make an shuffled array of integer [1:size] public static int[ ] shuffleArrGen(int size) { int rack [] = new int[size]; Random r = new Random(); for(int i=0;i<size;i++) { rack[i] = i+1; } for(int j=size-1;j>0;j--) { int idx = r.nextInt(j+1); int buff = rack[j]; rack[j] = rack[idx]; rack[idx] = buff; } return rack; } } 子节点建立一个通用的“nil”节点。

2 个答案:

答案 0 :(得分:2)

Java堆栈随平台(和VM标志)而变化,但通常为1MiB。即使假设每帧1KiB,那也是> 1000帧,即除非您的VM通过标志设置了非常小的堆栈。

正如评论者已经指出的那样,此代码在堆栈上保留的最大帧数为height(tree)。这意味着树可能有问题。

对此假设进行了简单的测试:向方法添加int level参数(显然将level+1传递给嵌套调用)并在每次调用时打印它以查看它有多高。如果它变为~1000,那么检查树。如果它保持在~10左右,那么检查堆栈大小。

无关:不需要为(lSHeight ==0 && rSHeight ==0)单独进行测试,因为Math.max()已经为此案做了正确的事。

答案 1 :(得分:1)

我将回答我自己的问题,因为我刚调试它,我觉得别人可以浪费时间来研究这个问题。 该错误是我没有使fost()方法正确,具体而言,我忘了将tempD连接到它的新父级(而parent确实连接到tempD null),假设父级不是always fully test out the current component before moving to the next parent

我在这里学到的真正教训是 ^.*(days|happy\s*\w*) ,如果我完成了旋转,那么它将不会花费这么多。

谢谢你们的帮助!