我有一个红色黑树实现,我使用CLRS中的伪代码实现,并且我在插入修复过程中遇到了NPE。这是我在java中的实现。 (忽略变量名称,我知道它不是惯例)
private RbtNode root;
private RbtNode nil;
private static final boolean BLACK = true;
private static final boolean RED = false;
public RedBlackTreeImpl() {
nil = new RbtNode("");
nil.color = BLACK;
root = nil;
}
@Override
public void rbInsert(T data) {
RbtNode z = new RbtNode(data);
RbtNode y = this.nil;
RbtNode x = this.root;
while(x != this.nil){
y = x;
if(z.data.toString().compareTo(x.data.toString()) < 0){
x = x.left;
} else {
x = x.right;
}
}
z.parent = y;
if(y == this.nil) {
this.root = z;
} else {
y.right = z;
}
z.left = this.nil;
z.right = this.nil;
z.color = RED;
rbInsertFixup(z);
}
@Override
public void rbInsertFixup(RbtNode z) {
while(z.parent.color == RED){
if(z.parent == z.parent.parent.left){
RbtNode y = z.parent.parent.right;
if(y.color == RED){
z.parent.color = BLACK;
y.color = BLACK;
z.parent.parent.color = RED;
z = z.parent.parent;
} else if(z == z.parent.right){
z = z.parent;
leftRotate(z.parent.parent);
}
z.parent.color = BLACK;
z.parent.parent.color = RED;
rightRotate(z.parent.parent);
} else {
RbtNode y = z.parent.parent.left;
if(y.color == RED){
z.parent.color = BLACK;
y.color = BLACK;
z.parent.parent.color = RED;
z = z.parent.parent;
} else if(z == z.parent.left){
z = z.parent;
rightRotate(z.parent.parent);
}
z.parent.color = BLACK;
z.parent.parent.color = RED;
leftRotate(z.parent.parent);
}
}
this.root.color = BLACK;
}
@Override
public void leftRotate(RbtNode x) {
RbtNode y = x.right;
x.right = y.left;
if(y.left != this.nil) {
y.left.parent = x;
}
y.parent = x.parent;
if(x.parent == this.nil){
this.root = y;
} else if(x == x.parent.left){
x.parent.left = y;
} else {
x.parent.right = y;
}
y.left = x;
x.parent = y;
}
@Override
public void rightRotate(RbtNode x) {
RbtNode y = x.left;
x.left = y.right;
if(y.right != this.nil) {
y.right.parent = x;
}
y.parent = x.parent;
if(x.parent == this.nil){
this.root = y;
} else if(x == x.parent.right){
x.parent.right = y;
} else {
x.parent.left = y;
}
y.right = x;
x.parent = y;
}
节点类
public class RbtNode<T> {
T data;
boolean color; //true indicates black; false indicates red
RbtNode<T> left;
RbtNode<T> right, parent;
public RbtNode(T data) {
if (data == null) {
throw new IllegalArgumentException("Data cannot be null");
}
this.data = data;
}
public boolean getColor() {
return this.color;
}
public T getData() {
return this.data;
}
public RbtNode<T> left() {
return left;
}
public RbtNode<T> right() {
return right;
}
public RbtNode<T> parent() {
return parent;
}
}
如果像上面那样运行测试插入:
RedBlackTreeImpl rbt = new RedBlackTreeImpl();
rbt.rbInsert("a");
rbt.rbInsert("k");
rbt.rbInsert("q");
rbt.rbInsert("c");
rbt.rbInsert("j");
rbt.rbInsert("e");
尝试插入"c"
时会发生NPE。具体地位于rbInsertFixup
的{{1}}位于z.parent.parent.color = RED;
的{{1}}的{{1}}之前的rightRotate
内。在该实例中if
1}}是while
,因此z
的父级是root
,所以它试图获得root
的父级实际上是nil
。
我尝试使nil
的左,右和父节点等于nil,但这会导致无限循环。我认为这归结为缺乏概念问题。所以我想我的问题可以分解成一个或两个问题。 我是否已经获得NPE标志,我应该继续这个过程,或者我是否设置了nil?我错过了什么?