I am trying to implement a red-black tree in Java and my remove()
function is having an issue where it's throwing a NullPointerException
.
First off, I create a root and insert to my red-black tree like so:
public void create(String word) { root = new RedBlackTree<String>(word); }
public void insert(String word) { root.add(word); }
Then I have a GUI where I can choose to remove a certain node using the word
. For some reason, I must manually insert into the r-b tree the same word that I want to delete. (By the way, the insert function increments a word occurrence variable and just add's one two the node's data value. So every node has a unique word.) After I insert, I can remove it without a NullPointerException
. But if I just try to remove the word before I manually insert, it will throw an exception. Even though the word is in the tree based on my insert()
function the tree seems to not find it.
Note: Every insertion to the tree has a key which is the word, and automatically starts with an occurrence of 1 as the data. Inserting the same word will increment the occurrence.
Remove function:
public RedBlackTree<E> remove(String c)
{
// find the target node - the node whose value is removed
RedBlackTree<E> target = locate(c);
if (target.isEmpty()) return root();
// determine the node to be disconnected:
// two cases: if degree < 2 we remove target node;
// otherwise, remove predecessor
RedBlackTree<E> freeNode;
if (target.left().isEmpty() ||
target.right().isEmpty()) // simply re-root tree at right
{
// < two children: target node is easily freed
freeNode = target;
} else {
// two children: find predecessor
freeNode = target.left();
while (!freeNode.right().isEmpty())
{
freeNode = freeNode.right();
}
// freeNode is predecessor
}
target.key = freeNode.key; // move value reference
// child will be orphaned by the freeing of freeNode;
// reparent this child carefully (it may be EMPTY)
RedBlackTree<E> child;
if (freeNode.left().isEmpty())
{
child = freeNode.right();
} else {
child = freeNode.left();
}
// if child is empty, we need to set its parent, temporarily
child.setParent(freeNode.parent());
if (!freeNode.isRoot())
{
if (freeNode.isLeftChild())
{
freeNode.parent().setLeft(child);
} else {
freeNode.parent().setRight(child);
}
}
// Assertion: child has been reparented
RedBlackTree<E> result = child.root();
if (freeNode.isBlack()) child.blackFixup();
return result.root();
}
Assisting functions:
public RedBlackTree(String v)
{
key = v;
data = 1;
parent = null;
left = right = new RedBlackTree<E>();
isRed = false; // roots of tree should be colored black
}
public boolean isEmpty()
{
return key == null;
}
protected RedBlackTree<E> locate(String c)
{
if (isEmpty()) return null;
int relation = c.compareTo(value());
if (relation == 0) return this;
if (relation < 0) return left().locate(c);
else return right().locate(c);
}
public RedBlackTree<E> add(String c)
{
RedBlackTree<E> tree = insert(c); // first, do a plain insert
tree.setRed(); // we insert nodes as red nodes - a first guess
tree.redFixup(); // now, rebalance the tree
return tree.root(); // return new root
}
protected RedBlackTree<E> insert(String c)
{
// trivial case - tree was empty:
if (isEmpty()) return new RedBlackTree<E>(c);
//System.out.println(locate(c));
if (!key.equals(c)) {
// decide to insert value to left or right of root:
if (c.compareTo(value()) < 0) {
// if to left and no left child, we insert value as leaf
if (left().isEmpty()) {
RedBlackTree<E> result = new RedBlackTree<E>(c);
setLeft(result);
return result;
} else {
// recursively insert to left
return left().insert(c);
}
} else {
// if to right and no left child, we insert value as leaf
if (right().isEmpty()) {
RedBlackTree<E> result = new RedBlackTree<E>(c);
setRight(result);
return result;
} else {
// recursively insert to right
return right().insert(c);
}
}
} else {
data++;
return this;
}
}