我正在尝试为二叉搜索树实现splay(Node x)方法。我正确地实现了leftRotation(Node x)和rightRotation(Node x)方法(至少,我认为它们是...),但是当我尝试在splay(Node x)方法中实现它们时,它会调用自己无限循环。现在,我知道它为什么这样做,但似乎无法弄清楚如何修复它。
这是leftRotation(Node x)方法:
public void leftRotation(Node<E> x) {
if (x.getRightChild() == null) {
return;
}
Node<E> y = x.getRightChild();
x.setRightChild(y.getLeftChild());
if (y.getLeftChild() != null) {
y.getLeftChild().setParent(x);
}
y.setParent(x.getParent());
if (x.getParent() == null) {
root = y;
} else {
if (x == x.getParent().getLeftChild()) {
x.getParent().setLeftChild(y);
} else {
x.getParent().setRightChild(y);
}
}
y.setLeftChild(x);
x.setParent(y);
}
这里是rightRotation(节点x)方法:
public void rightRotation(Node<E> x) {
if (x.getLeftChild() == null) {
return;
}
Node<E> y = x.getLeftChild();
x.setRightChild(y.getRightChild());
if (y.getRightChild() != null) {
y.getRightChild().setParent(x);
}
y.setParent(x.getParent());
if (x.getParent() == null) {
root = y;
} else {
if (x == x.getParent().getRightChild()) {
x.getParent().setRightChild(y);
} else {
x.getParent().setLeftChild(y);
}
}
x.setRightChild(x);
x.setParent(y);
}
这是splay(Node x)方法:
public void splay(Node<E> x) {
while (x.getParent() != null) {
if (x.isLeftChild && x.getParent().isLeftChild) {
this.rightRotation(x.getParent());
this.rightRotation(x);
} else if (x.isRightChild && x.getParent().isRightChild) {
this.leftRotation(x.getParent());
this.leftRotation(x);
} else if (x.isLeftChild && x.getParent().isRightChild) {
this.rightRotation(x);
this.leftRotation(x);
} else if (x.isRightChild() && x.getParent().isLeftChild()) {
this.leftRotation(x);
this.rightRotation(x);
} else if (x.isLeftChild && x.getParent() == root) {
this.rightRotation(x);
} else if (x.isRightChild && x.getParent() == root) {
this.leftRotation(x);
}
}
}
关于如何修复无限循环的任何想法?它似乎与splay(Node x)方法中的while(x.getParent()!= null)语句不一致,但是当我使用调试器完成代码时,它的属性节点似乎在变化,所以我真的不知道它出了什么问题?
setLeftChild(Node leftChild)方法:
public void setLeftChild(Node<E> leftChild) {
this.leftChild = leftChild;
if (leftChild != null) {
leftChild.setIsRightChild(true);
leftChild.setParent(this);
}
}
答案 0 :(得分:0)
除了我在代码中指出的所有错误/错误之外,这里是rightRotation
中最大的错误/错误:
x.setRightChild(x);
这会在树中创建一个循环,因此会产生无限循环。你应该对你的方法进行单元测试。您的代码中的另一个主要错误是您的if - else if
指令没有else
,因此可能会出现迭代期间没有任何反应的情况......因此无限循环。这不是这里的情况,因为你考虑了所有的情况(实际上,你考虑的更多,最后两个将永远不会被执行,因为前四个案例涵盖了所有可能的情况)但作为一般评论,这是以这种方式编码非常危险。
以下是我自己实现所有这些方法的代码,我认为它更清晰:
public class BinaryTree<T extends Comparable<T>> {
private Node<T> root;
public void rebalance(Node<T> node) {
while (!node.isRoot()) rotation(node.getParent(), node.getChildKind().opposite());
}
private void rotation(Node<T> node, Side side) {
if (node.getChild(side.opposite()) == null) return;
Node<T> sideChild = node.getChild(side.opposite());
node.setChild(sideChild.getChild(side), side.opposite());
if (node.getParent() == null) setRoot(sideChild);
else node.getParent().setChild(sideChild, node.getChildKind());
sideChild.setChild(node, side);
}
private void setRoot(Node<T> root) {
this.root = root;
if (root != null) root.setRoot();
}
private static enum Side {
LEFT, RIGHT;
public Side opposite() { return this == LEFT ? RIGHT : LEFT; }
}
private static class Node<T extends Comparable<T>> {
private T value;
private Node<T> left, right, parent;
public Node(T value) { this(value, null, null, null); }
public Node(T value, Node<T> left, Node<T> right, Node<T> parent) {
setValue (value );
setLeft (left );
setRight (right );
setParent(parent);
}
public Node<T> setLeft(Node<T> left) {
this.left = left;
if (left != null) left.parent = this;
return this;
}
public Node<T> setRight(Node<T> right) {
this.right = right;
if (right != null) right.parent = this;
return this;
}
public Node<T> setChild(Node<T> child, Side side) { return side == Side.LEFT ? setLeft(child) : setRight(child); }
public Node<T> setRoot() { return setParent(null); }
private Node<T> setParent(Node<T> parent) {
this.parent = parent;
return this;
}
public Node<T> setValue(T value) {
this.value = notNull(value);
return this;
}
public boolean isRoot() { return parent == null; }
public boolean isLeftChild () { return isRoot() || getParent().getValue().compareTo(getValue()) > 0; }
public boolean isRightChild() { return isRoot() || !isLeftChild() ; }
public Node<T> getChild(Side side) { return side == Side.LEFT ? getLeft() : getRight(); }
public Side getChildKind() {
Check.isFalse(isRoot(), "This method is not defined on root nodes");
return isLeftChild() ? Side.LEFT : Side.RIGHT;
}
public T getValue () { return value ; }
public Node<T> getLeft () { return left ; }
public Node<T> getRight () { return right ; }
public Node<T> getParent() { return parent; }
}
}
注意:我的树并不总是以最佳方式重新平衡。我做了这件事,但是我会在维基百科看看他们说的话,我可能没有应用正确的算法,但它在病理案例中已经很好用。