I have a red black tree implementation that I have implemented from pseudo code found in the CLRS and I'm running into a NPE in the insert fixup procedure. Here is my implementation in java. (Ignore the variable names, I know it's not convention)
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;
}
Node Class
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;
}
}
If run a test insert on it like such:
RedBlackTreeImpl rbt = new RedBlackTreeImpl();
rbt.rbInsert("a");
rbt.rbInsert("k");
rbt.rbInsert("q");
rbt.rbInsert("c");
rbt.rbInsert("j");
rbt.rbInsert("e");
The NPE occurs when attempting to insert "c"
. Specifically at in rbInsertFixup
on the line z.parent.parent.color = RED;
immediately before the rightRotate
within the first if
of the while
loop. In that instance z
is root
, so root
's parent is nil
, and so it's trying to get nil
's parent which is actually null
.
I tried making nil
's left, right, and parent nodes equal to nil, but that caused an infinite loop. I think this comes down to a lack of concepts issue. So I suppose my question could be broken into an either or question. Is the fact that I'm getting a NPE a sign that I should continue the process, or have I set up nil incorrectly? What is it that I'm missing?