Data Structure - Red Black Tree (Java)
阿新 • • 發佈:2018-12-29
package chimomo.learning.java.datastructure; /** * Implements a red-black tree. * Note that all "matching" is based on the compareTo method. * * @author Created by Chimomo */ public class RedBlackTree<T extends Comparable<? super T>> { // BLACK must be 1. private static final int BLACK = 1; private static final int RED = 0; private RedBlackNode<T> header; private RedBlackNode<T> nullNode; // Used in insert routine and its helpers. private RedBlackNode<T> current; private RedBlackNode<T> parent; private RedBlackNode<T> grand; private RedBlackNode<T> great; /** * Construct the tree. */ public RedBlackTree() { nullNode = new RedBlackNode<>(null); nullNode.left = nullNode.right = nullNode; header = new RedBlackNode<>(null); header.left = header.right = nullNode; } // Test program public static void main(String[] args) throws Exception { // Construct RedBlackTree. RedBlackTree<Integer> t = new RedBlackTree<>(); final int NUMS = 400000; final int GAP = 35461; System.out.println("Checking... (no more output means success)"); // Insert. for (int i = GAP; i != 0; i = (i + GAP) % NUMS) { t.insert(i); } // Find min and find max. if (t.findMin() != 1 || t.findMax() != NUMS - 1) { System.out.println("FindMin or FindMax error!"); } // Contains. for (int i = 1; i < NUMS; i++) { if (!t.contains(i)) { System.out.println("Find error1!"); } } } /** * Compare item and t.element using compareTo with caveat that if t is header, then item is always larger. * This routine is called if is possible that t is header. * If it is not possible for t to be header, use compareTo directly. */ private int compare(T item, RedBlackNode<T> t) { if (t == header) { return 1; } else { return item.compareTo(t.element); } } /** * Insert into the tree. * * @param item The item to insert. */ public void insert(T item) { current = parent = grand = header; nullNode.element = item; while (compare(item, current) != 0) { great = grand; grand = parent; parent = current; current = compare(item, current) < 0 ? current.left : current.right; // Check if two red children; fix if so. if (current.left.color == RED && current.right.color == RED) reorient(item); } // Insertion fails if already present. if (current != nullNode) { return; } current = new RedBlackNode<>(item, nullNode, nullNode); // Attach to parent. if (compare(item, parent) < 0) { parent.left = current; } else { parent.right = current; } reorient(item); } /** * Remove from the tree. * * @param x The item to remove. * @throws UnsupportedOperationException If called. */ public void remove(T x) { throw new UnsupportedOperationException(); } /** * Find the smallest item the tree. * * @return The smallest item or throw exception if empty. */ public T findMin() throws Exception { if (isEmpty()) { throw new Exception("Red-Black tree is empty!"); } RedBlackNode<T> itr = header.right; while (itr.left != nullNode) { itr = itr.left; } return itr.element; } /** * Find the largest item in the tree. * * @return The largest item or throw exception if empty. */ public T findMax() throws Exception { if (isEmpty()) { throw new Exception("Red-Black tree is empty!"); } RedBlackNode<T> itr = header.right; while (itr.right != nullNode) { itr = itr.right; } return itr.element; } /** * Find an item in the tree. * * @param x The item to search for. * @return True if x is found, false otherwise. */ public boolean contains(T x) { nullNode.element = x; current = header.right; for (; ; ) { if (x.compareTo(current.element) < 0) { current = current.left; } else if (x.compareTo(current.element) > 0) { current = current.right; } else if (current != nullNode) { return true; } else { return false; } } } /** * Make the tree logically empty. */ public void makeEmpty() { header.right = nullNode; } /** * Print the tree contents in sorted order. */ public void printTree() { if (isEmpty()) { System.out.println("Red-Black tree is empty!"); } else { printTree(header.right); } } /** * Internal method to print a subtree in sorted order. * * @param t The node that roots the subtree. */ private void printTree(RedBlackNode<T> t) { if (t != nullNode) { printTree(t.left); System.out.println(t.element); printTree(t.right); } } /** * Test if the tree is logically empty. * * @return True if empty, false otherwise. */ public boolean isEmpty() { return header.right == nullNode; } /** * Internal routine that is called during an insertion if a node has two red children. * Performs flip and rotations. * * @param item The item being inserted. */ private void reorient(T item) { // Do the color flip. current.color = RED; current.left.color = BLACK; current.right.color = BLACK; // Have to rotate. if (parent.color == RED) { grand.color = RED; // Start double rotate. if ((compare(item, grand) < 0) != (compare(item, parent) < 0)) { parent = rotate(item, grand); } current = rotate(item, great); current.color = BLACK; } // Make root black. header.right.color = BLACK; } /** * Internal routine that performs a single or double rotation. * Because the result is attached to the parent, there are four cases. * Called by reorient. * * @param item The item in reorient. * @param parent The parent of the root of the rotated subtree. * @return The root of the rotated subtree. */ private RedBlackNode<T> rotate(T item, RedBlackNode<T> parent) { if (compare(item, parent) < 0) { return parent.left = compare(item, parent.left) < 0 ? rotateWithLeftChild(parent.left) : // LL rotateWithRightChild(parent.left); // LR } else { return parent.right = compare(item, parent.right) < 0 ? rotateWithLeftChild(parent.right) : // RL rotateWithRightChild(parent.right); // RR } } /** * Rotate binary tree node with left child. */ private RedBlackNode<T> rotateWithLeftChild(RedBlackNode<T> k2) { RedBlackNode<T> k1 = k2.left; k2.left = k1.right; k1.right = k2; return k1; } /** * Rotate binary tree node with right child. */ private RedBlackNode<T> rotateWithRightChild(RedBlackNode<T> k1) { RedBlackNode<T> k2 = k1.right; k1.right = k2.left; k2.left = k1; return k2; } /** * Red-Black node class for Red-Black tree. * * @param <AnyType> Any type. */ private static class RedBlackNode<AnyType> { AnyType element; // The data in the node. RedBlackNode<AnyType> left; // Left child. RedBlackNode<AnyType> right; // Right child. int color; // Color. // Constructors. RedBlackNode(AnyType element) { this(element, null, null); } RedBlackNode(AnyType element, RedBlackNode<AnyType> left, RedBlackNode<AnyType> right) { this.element = element; this.left = left; this.right = right; color = RedBlackTree.BLACK; } } } /* Output: Checking... (no more output means success) */