我正在进行一项要求我实现AVL树的作业。我很确定我的旋转方法是正确的,但是我无法确定何时使用它们。
例如,书中的解释说我应该爬上我向下插入节点/元素的路径。但是,我不能有任何父指针。
最新代码:
public BinaryNode<T> insert(BinaryNode<T> node) {
if (this.getElement().compareTo(node.getElement()) > 0) {
if (this.getLeftChild() != null) {
BinaryNode<T> b = this.getLeftChild().insert(node);
if(!this.isBalanced()) {
this.balance();
}
return b;
} else {
this.setLeftChild(node);
}
} else if (this.getElement().compareTo(node.getElement()) < 0) {
if (this.getRightChild() != null) {
return this.getRightChild().insert(node);
} else {
this.setRightChild(node);
}
}
return this;
}
我想在这里做的是爬回树上,但它只能在插入节点后检查平衡。因此,这是在else子句中。
我也尝试将余额代码放在R Samuel Klatchko建议的地方,但检查了每个插页的余额。例如:如果连续插入7,9,5,3和1,则在尝试插入1时会出现空指针异常。
编辑:上述原因之一可能与我做高度的方式有关。如果我每次用height()计算高度但是会破坏AVL树的O(log(n))时间,它可以正常旋转。
关于如何做到这一点的任何想法?
答案 0 :(得分:3)
你的代码正在向上攀升。请考虑以下代码:
if (this.getLeftChild() != null) {
return this.getLeftChild().insert(node);
}
并稍加修改:
if (this.getLeftChild() != null) {
boolean b = this.getLeftChild().insert(node);
// do something here
return b;
}
当代码从递归调用返回时,每次返回都会将您带回父级。如果不立即返回递归调用的值,您就有机会进行重新平衡。
更新最新代码
当您插入右侧时,不要忘记重新平衡。
答案 1 :(得分:1)
您可以尝试将父指针传递到insert
方法,或者您可以将insert
转换为迭代方法并保留一个显式堆栈,在该堆栈上记录树中的路径。
顺便说一下,为了选择要使用的旋转,你可以知道节点是不平衡的,你必须知道更深的子树是在右边还是在左边。这意味着您的简单isBalanced
方法还不够。它效率也很低,并且会破坏AVL树的 O(log n)复杂度,因为你每次都会计算出高度。