我发现successor并不是简单的Hibbard算法就可以的,Hibbard似乎只适合删除,因为删除的时候已经确认左子树和右子树都存在在。但计算successor并不是,比如课程的例子的树:
5
/
3 6
/ \
2 4 8
5、3、6可以使用Hibbard搞定,但2、4、8不可以。我发现只有被查节点存在右子树,才可以用Hibbard,比如图中的2不存在右子树,无法使用。那应该怎么做呢?我自己观察了一下,要先判断自身是parent的左子还是右子,如果是左子,则父节点即是successor,因为此时parent刚刚好比node大一点点,如果自身是parent的右子,则情况很麻,要判断parent是grandParent的左子还是右子,并且需要循环向上找parent,直到找到为左子的祖先parent。先写一下伪代码:
if (node 是左子) {
successor = parent
}
if (node = 是右子) {
while(true) {
if (parent 是左子) {
successor = parent.parent
}
parent = parent.parent
}
}
我根据这种想法实现了代码,跟老师的Node相比,我多维护了parent、nodeType等成员变量,最终successor的求解是:
public E successor(E e) {
if (contains(e)) {
Node<E> successorNode = getSuccessorByHibbarb(root, e);
if (successorNode == null) {
successorNode = getSuccessorByBian(root, e);
}
return successorNode == null ? null : successorNode.e;
}else {
return e;
}
}
public Node<E> getSuccessorByHibbarb(Node<E> node, E e) {
if (e.compareTo(node.e) == 0) {
Node<E> resNode = null;
if (node.left == null) {
resNode = node.right;
} else if (node.right == null) {
resNode = node.left;
} else {
return minimum(node.right);
}
node = null;
return resNode;
}
if (e.compareTo(node.e) < 0) {
return getSuccessorByHibbarb(node.left, e);
}else {
return getSuccessorByHibbarb(node.right, e);
}
}
public Node<E> getSuccessorByBian(Node<E> node, E e) {
if (e.compareTo(node.e) == 0) {
if (node.isLeftChild()) {
return node.parent;
}
if (node.isRightChild()) {
Node<E> turnNode = node.parent;
while (true) {
if (turnNode.isLeftChild()) {
return turnNode.parent;
}
if (turnNode.isRoot()) {
return null;
}
turnNode = turnNode.parent;
}
}
}
if (e.compareTo(node.e) < 0) {
return getSuccessorByBian(node.left, e);
}else {
return getSuccessorByBian(node.right, e);
}
}
我测试了代码,在少量数据的时候是可以得到正确答案的,请问老师,是我想复杂了嘛?求successor有更简单的办法嘛?