blob: 9caa0a31d78bf60e94b042d72d3be87663139d3f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.internal.util.rb_trees;
import org.apache.uima.internal.util.BinaryTree;
/**
* Red-Black Tree node. Not for public use. Use the interface in RedBlackTree instead. This should
* probably be an internal class to RedBlackTree, but it's easier to read in a seperate file. See
* comments in RedBlackTree.
*
*/
class RBTNode<T> {
// The colors.
private static final boolean RED = true;
private static final boolean BLACK = false;
private int key; // The key of the node.
private boolean color; // The color of the node.
// A pointer to the parent node. This will be null if this is the
// root of a tree.
private RBTNode<T> parent;
// The following variables are package private so they can be
// accessed from RedBlackTree.
RBTNode<T> left; // The left daughter.
RBTNode<T> right; // The right daughter.
T element; // The element contained in the node.
// For the debugging print functions.
private static final int indentInc = 2;
/**
* The real constructor, used only internally.
*/
private RBTNode(int key, boolean color, RBTNode<T> parent, RBTNode<T> left, RBTNode<T> right,
T element) {
this.key = key;
this.color = color;
this.parent = parent;
this.left = left;
this.right = right;
this.element = element;
}
/**
* The standard constructor as used by RedBlackTree.
*
* @param key
* The key to be inserted.
* @param element
* The value to be inserted.
*/
RBTNode(int key, T element) {
// The default color is completely arbitrary.
this(key, BLACK, null, null, null, element);
}
/**
* Find a node with a certain key. Returns null if no such node exists.
*/
static final <T> RBTNode<T> find(RBTNode<T> x, int key) {
while (x != null && x.key != key) {
if (key < x.key) {
x = x.left;
} else {
x = x.right;
}
}
return x;
}
/**
* Find the successor node to this.
*/
final RBTNode<T> successor() {
RBTNode<T> x = this;
// If this has a right daughter, then the successor will be the
// leftmost daughter of this.right, if it exists, and x.right,
// else.
if (x.right != null) {
x = x.right;
while (x.left != null) {
x = x.left;
}
return x;
}
// If this does not have a right daughter, we need to move up in
// the tree until we hit a node we're the left daughter of. That
// will be the successor.
RBTNode<T> y = x.parent;
while (y != null && x == y.right) {
x = y;
y = x.parent;
}
return y;
}
/**
* Insert a node into a tree. See CLR.
*/
static final <T> boolean insert(RedBlackTree<T> tree, RBTNode<T> x) {
if (!treeInsert(tree, x)) {
// A node with the same key as x already existed in the tree, so
// there is nothing left to do.
return false;
}
RBTNode<T> y;
x.color = RED;
while (x != tree.root && x.parent.color == RED) {
if (x.parent == x.parent.parent.left) {
y = x.parent.parent.right;
if (colorOf(y) == RED) {
x.parent.color = BLACK;
setColor(y, BLACK);
x.parent.parent.color = RED;
x = x.parent.parent;
} else {
if (x == x.parent.right) {
x = x.parent;
x.leftRotate(tree);
}
x.parent.color = BLACK;
x.parent.parent.color = RED;
x.parent.parent.rightRotate(tree);
}
} else {
y = x.parent.parent.left;
if (colorOf(y) == RED) {
x.parent.color = BLACK;
setColor(y, BLACK);
x.parent.parent.color = RED;
x = x.parent.parent;
} else {
if (x == x.parent.left) {
x = x.parent;
x.rightRotate(tree);
}
x.parent.color = BLACK;
x.parent.parent.color = RED;
x.parent.parent.leftRotate(tree);
}
}
}
tree.root.color = BLACK;
return true;
}
/** Auxiliary function for insert(). See CLR. */
private static final <T> boolean treeInsert(RedBlackTree<T> tree, RBTNode<T> z) {
RBTNode<T> y = null;
RBTNode<T> x = tree.root;
while (x != null) {
y = x;
if (z.key < x.key) {
x = x.left;
} else if (z.key > x.key) {
x = x.right;
} else { // z.key == x.key
x.element = z.element;
// No node was actually inserted.
return false;
}
}
z.parent = y;
if (y == null) {
tree.root = z;
} else if (z.key < y.key) {
y.left = z;
} else {
y.right = z;
}
return true;
}
/** Left rotation, used to keep the tree balanced. See CLR. */
private final void leftRotate(RedBlackTree<T> tree) {
RBTNode<T> y = this.right;
this.right = y.left;
if (y.left != null) {
y.left.parent = this;
}
y.parent = this.parent;
if (this.parent == null) {
tree.root = y;
} else if (this == this.parent.left) {
this.parent.left = y;
} else {
this.parent.right = y;
}
y.left = this;
this.parent = y;
return;
}
/** Right rotation, used to keep the tree balanced. See CLR. */
private final void rightRotate(RedBlackTree<T> tree) {
RBTNode<T> y = this.left;
this.left = y.right;
if (y.right != null) {
y.right.parent = this;
}
y.parent = this.parent;
if (this.parent == null) {
tree.root = y;
} else if (this == this.parent.right) {
this.parent.right = y;
} else {
this.parent.left = y;
}
y.right = this;
this.parent = y;
return;
}
/**
* Delete a given node from the tree. The node must be contained in the tree! Our code is more
* complicated than CLR because we don't use a NIL sentinel.
*/
static final <T> void delete(RedBlackTree<T> tree, RBTNode<T> z) {
RBTNode<T> x;
RBTNode<T> y;
RBTNode<T> xParent = null;
if (z.left == null || z.right == null) {
y = z;
} else {
y = z.successor();
}
if (y.left != null) {
x = y.left;
} else {
x = y.right;
}
if (x != null) {
x.parent = y.parent;
} else {
xParent = y.parent;
}
if (y.parent == null) {
tree.root = x;
} else {
if (y == y.parent.left) {
y.parent.left = x;
} else {
y.parent.right = x;
}
}
if (y != z) {
z.key = y.key;
z.element = y.element;
}
if (y.color == BLACK) {
if (x == null) {
deleteFixupNull(tree, xParent);
} else {
deleteFixup(tree, x);
}
}
}
/**
* From CLR. x must not be null.
*/
private static final <T> void deleteFixup(RedBlackTree<T> tree, RBTNode<T> x) {
RBTNode<T> w;
while (x != tree.root && x.color == BLACK) {
if (x == x.parent.left) {
w = x.parent.right;
if (w.color == RED) {
w.color = BLACK;
x.parent.color = RED;
x.parent.leftRotate(tree);
w = x.parent.right;
}
if (colorOf(leftOf(w)) == BLACK && colorOf(rightOf(w)) == BLACK) {
w.color = RED;
x = x.parent;
} else {
if (colorOf(rightOf(w)) == BLACK) {
w.color = RED;
w.rightRotate(tree);
w = x.parent.right;
}
w.color = x.parent.color;
x.parent.color = BLACK;
if (w.right != null) {
w.right.color = BLACK;
}
x.parent.leftRotate(tree);
x = tree.root;
}
} else {
w = x.parent.left;
if (w.color == RED) {
w.color = BLACK;
x.parent.color = RED;
x.parent.rightRotate(tree);
w = x.parent.left;
}
if (colorOf(rightOf(w)) == BLACK && colorOf(leftOf(w)) == BLACK) {
w.color = RED;
x = x.parent;
} else {
if (colorOf(leftOf(w)) == BLACK) {
w.color = RED;
w.leftRotate(tree);
w = x.parent.left;
}
w.color = x.parent.color;
x.parent.color = BLACK;
if (w.left != null) {
w.left.color = BLACK;
}
x.parent.rightRotate(tree);
x = tree.root;
}
}
}
x.color = BLACK;
}
/**
* Like deleteFixup(), only that the node we should be working on is null, and we actually hand in
* the node's mother. Special case because we don't use sentinels.
*/
private static final <T> void deleteFixupNull(RedBlackTree<T> tree, RBTNode<T> x) {
// if x == null, we just deleted the only node in the tree
if (x == null) {
return;
}
RBTNode<T> w;
if (x.left == null) {
w = x.right;
if (w.color == RED) {
w.color = BLACK;
x.color = RED;
x.leftRotate(tree);
w = x.right;
}
if (colorOf(leftOf(w)) == BLACK && colorOf(rightOf(w)) == BLACK) {
w.color = RED;
} else {
if (colorOf(rightOf(w)) == BLACK) {
w.color = RED;
w.rightRotate(tree);
w = x.right;
}
w.color = x.color;
x.color = BLACK;
if (w.right != null) {
w.right.color = BLACK;
}
x.leftRotate(tree);
x = tree.root;
}
} else {
w = x.left;
if (w.color == RED) {
w.color = BLACK;
x.color = RED;
x.rightRotate(tree);
w = x.left;
}
if (colorOf(rightOf(w)) == BLACK && colorOf(leftOf(w)) == BLACK) {
w.color = RED;
} else {
if (colorOf(leftOf(w)) == BLACK) {
w.color = RED;
w.leftRotate(tree);
w = x.left;
}
w.color = x.color;
x.color = BLACK;
if (w.left != null) {
w.left.color = BLACK;
}
x.rightRotate(tree);
x = tree.root;
}
}
while (x != tree.root && x.color == BLACK) {
if (x == x.parent.left) {
w = x.parent.right;
if (w.color == RED) {
w.color = BLACK;
x.parent.color = RED;
x.parent.leftRotate(tree);
w = x.parent.right;
}
if (colorOf(leftOf(w)) == BLACK && colorOf(rightOf(w)) == BLACK) {
w.color = RED;
x = x.parent;
} else {
if (colorOf(rightOf(w)) == BLACK) {
w.color = RED;
w.rightRotate(tree);
w = x.parent.right;
}
w.color = x.parent.color;
x.parent.color = BLACK;
if (w.right != null) {
w.right.color = BLACK;
}
x.parent.leftRotate(tree);
x = tree.root;
}
} else {
w = x.parent.left;
if (w.color == RED) {
w.color = BLACK;
x.parent.color = RED;
x.parent.rightRotate(tree);
w = x.parent.left;
}
if (colorOf(rightOf(w)) == BLACK && colorOf(leftOf(w)) == BLACK) {
w.color = RED;
x = x.parent;
} else {
if (colorOf(leftOf(w)) == BLACK) {
w.color = RED;
w.leftRotate(tree);
w = x.parent.left;
}
w.color = x.parent.color;
x.parent.color = BLACK;
if (w.left != null) {
w.left.color = BLACK;
}
x.parent.rightRotate(tree);
x = tree.root;
}
}
}
x.color = BLACK;
}
/**
* Fill an array with the keys contained in the tree. The array must at least have the size of the
* tree! Returns the size of the tree, for internal reasons.
*/
int keys(int pos, int[] keys) {
int cur = pos;
if (this.left != null) {
cur = this.left.keys(cur, keys);
}
keys[cur] = this.key;
++cur;
if (this.right != null) {
cur = this.right.keys(cur, keys);
}
return cur;
}
// Use as accessor when node might be null.
private static final <T> boolean colorOf(RBTNode<T> x) {
return (x == null) ? BLACK : x.color;
}
// Below some accessor functions to be used when the node might be
// null.
// Use when node might be null.
private static final <T> void setColor(RBTNode<T> x, boolean c) {
if (x != null) {
x.color = c;
}
}
// Use when node might be null.
private static final <T> RBTNode<T> leftOf(RBTNode<T> x) {
return (x == null) ? null : x.left;
}
// Use when node might be null.
private static final <T> RBTNode<T> rightOf(RBTNode<T> x) {
return (x == null) ? null : x.right;
}
// Debugging aid.
public void printKeys(int indent) {
for (int i = 0; i < indent; i++) {
System.out.print(' ');
}
System.out.print(this.key);
System.out.print(":");
if (this.color == RED) {
System.out.println("red");
} else {
System.out.println("black");
}
indent += indentInc;
if (this.left != null) {
this.left.printKeys(indent);
}
if (this.right != null) {
this.right.printKeys(indent);
}
return;
}
// Debugging aid.
public void printElements(int indent) {
for (int i = 0; i < indent; i++) {
System.out.print(' ');
}
System.out.println(this.element.toString());
indent += indentInc;
if (this.left != null) {
this.left.printElements(indent);
}
if (this.right != null) {
this.right.printElements(indent);
}
return;
}
void getBinaryTree(BinaryTree tree) {
tree.setValue(new RBTKeyValuePair(this.key, this.element));
if (this.left != null) {
BinaryTree newLeft = tree.newLeftDtr();
this.left.getBinaryTree(newLeft);
}
if (this.right != null) {
BinaryTree newRight = tree.newRightDtr();
this.right.getBinaryTree(newRight);
}
}
// public class PreorderIterator implements Iterator {
// private RBTNode current;
// private PreorderIterator() {
// this.current = null;
// }
// PreorderIterator(RBTNode node) {
// this.current = node;
// }
// public boolean hasNext() {
// return (this.current == null);
// }
// public Object next() {
// if (this.current == null) {
// throw new java.util.NoSuchElementException();
// }
// RBTNode node = this.current;
// // Return this at the end.
// final RBTKeyValuePair rv = new RBTKeyValuePair(node.key, node.element);
// // Find the next value.
// if (node.left != null) {
// // Go down left branch if it exists.
// node = node.left;
// } else if (node.right != null) {
// // Else, go down right branch, if it exists.
// node = node.right;
// } else {
// // Else, back up the tree.
// while (node.parent != null) {
// if (node == node.parent.right || node.parent.right == null) {
// // This is a right dtr or an only child, continue backing
// // up the tree.
// node = node.parent;
// } else {
// // This is a left dtr and a right dtr exists, so this is
// // our next candidate.
// node = node.parent.right;
// break;
// }
// }
// if (node.parent == null) {
// this.current = null;
// } else {
// this.current = node;
// }
// }
// return rv;
// }
// public void remove() {
// throw new java.lang.UnsupportedOperationException();
// }
// }
// java.util.Iterator preorderIterator() {
// return new PreorderIterator(this);
// }
}