Java 红黑树实现中的空指针
我有一个红黑树实现,它是从中找到的伪代码实现的,我在insert fixup过程中遇到了一个NPE。这是我的java实现。(忽略变量名,我知道这不是惯例) 在尝试插入Java 红黑树实现中的空指针,java,algorithm,nullpointerexception,red-black-tree,Java,Algorithm,Nullpointerexception,Red Black Tree,我有一个红黑树实现,它是从中找到的伪代码实现的,我在insert fixup过程中遇到了一个NPE。这是我的java实现。(忽略变量名,我知道这不是惯例) 在尝试插入“c”时,会发生NPE。特别是在z.parent.parent.color=RED行的rbInsertFixup中。在这种情况下z是根,因此根的父项是nil,因此它试图获取nil的父项,实际上是null 我尝试使nil的左、右和父节点等于nil,但这导致了无限循环。我认为这归结为一个缺乏概念的问题。所以我想我的问题可以分为非此即彼的
“c”
时,会发生NPE。特别是在z.parent.parent.color=RED行的rbInsertFixup
中在while
循环的第一个if
中,紧靠右旋转的前面的code>。
在这种情况下z
是根
,因此根
的父项是nil
,因此它试图获取nil
的父项,实际上是null
我尝试使
nil
的左、右和父节点等于nil,但这导致了无限循环。我认为这归结为一个缺乏概念的问题。所以我想我的问题可以分为非此即彼的问题我得到NPE的事实是否表明我应该继续这个过程,或者我设置的nil不正确?我遗漏了什么?异常发生在z.parent.parent.color=RED
很明显,z
,z.parent
,或z.parent.parent
在那一点上是空的。这是一个精确的副本吗?五分钟足够我浏览整个帖子并确定这一点吗?@nhouser9:这是显而易见的。我得了NPE。我甚至在我的帖子中解释了你的评论。但这不是我的问题…@JarrodRoberson这不是一个完全相同的副本,他知道什么是NPE以及如何调试它。事实上,在他的代码中,他展示了他已经完成了调试,并且知道空值在哪里——他正在寻找一个关于如何在不偏离他发现的算法的情况下纠正代码的解释。这本不应该被关闭。对,所以-这个问题可以回答,不是典型的NPE。有一点担心:像parent.parent
这样的东西是一种气味,特别是当树很浅的时候。可能的错误来自您没有考虑到您想要从右侧旋转的节点只有1级深的事实。异常发生在z.parent.parent.color=RED
很明显,z
,z.parent
,或z.parent.parent
在那一点上是空的。这是一个精确的副本吗?五分钟足够我浏览整个帖子并确定这一点吗?@nhouser9:这是显而易见的。我得了NPE。我甚至在我的帖子中解释了你的评论。但这不是我的问题…@JarrodRoberson这不是一个完全相同的副本,他知道什么是NPE以及如何调试它。事实上,在他的代码中,他展示了他已经完成了调试,并且知道空值在哪里——他正在寻找一个关于如何在不偏离他发现的算法的情况下纠正代码的解释。这本不应该被关闭。对,所以-这个问题可以回答,不是典型的NPE。有一点担心:像parent.parent
这样的东西是一种气味,特别是当树很浅的时候。可能的错误是由于您没有考虑要从右侧旋转的节点只有1层深这一事实。
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");