package iiuf.util; /** RedBalck tree implementation. (c) 1999, 2000, 2001, IIUF, DIUF<p> @author $Author: ohitz $ @version $Name: $ $Revision: 1.1 $ */ public class RedBlackTree extends BinaryTree { public static boolean RED = true; public static boolean BLACK = false; public RedBlackTree() { this(new RedBlackNode(-1, "NIL")); } public RedBlackTree(RedBlackNode nil) { super(nil); } public void add(TreeNode x) { super.add(x); RedBlackNode y; ((RedBlackNode)x).color = RED; while(x != root && ((RedBlackNode)x.p).color == RED) { if(x.p == ((BinaryTreeNode)x.p.p).left) { y = (RedBlackNode)((BinaryTreeNode)x.p.p).right; if(y.color == RED) { ((RedBlackNode)x.p).color = BLACK; y.color = BLACK; ((RedBlackNode)x.p.p).color = RED; x = (RedBlackNode)x.p.p; } else { if(((BinaryTreeNode)x.p).right == x) { x = (RedBlackNode)x.p; leftRotate((BinaryTreeNode)x); } ((RedBlackNode)x.p).color = BLACK; ((RedBlackNode)x.p.p).color = RED; rightRotate((BinaryTreeNode)x.p.p); } } else { y = (RedBlackNode)((BinaryTreeNode)x.p.p).left; if(y.color == RED) { ((RedBlackNode)x.p).color = BLACK; y.color = BLACK; ((RedBlackNode)x.p.p).color = RED; x = (RedBlackNode)x.p.p; } else { if(((BinaryTreeNode)x.p).left == x) { x = (RedBlackNode)x.p; rightRotate((BinaryTreeNode)x); } ((RedBlackNode)x.p).color = BLACK; ((RedBlackNode)x.p.p).color = RED; leftRotate((BinaryTreeNode)x.p.p); } } } ((RedBlackNode)root).color = BLACK; changed(); } public void remove(TreeNode z_) { if(z_ == NIL) return; BinaryTreeNode z = (BinaryTreeNode)z_; BinaryTreeNode y = z.left == NIL || z.right == NIL ? z : successor(z); BinaryTreeNode x = y.left != NIL ? y.left : y.right; x.p = y.p; if(y.p == NIL) root = x; else if(((BinaryTreeNode)y.p).left == y) ((BinaryTreeNode)y.p).left = x; else ((BinaryTreeNode)y.p).right = x; boolean delfix = ((RedBlackNode)y).color == BLACK; if(y != z) { y.p = z.p; y.left = z.left; y.right = z.right; ((RedBlackNode)y).color = ((RedBlackNode)z).color; if(root == z) root = y; else { if(((BinaryTreeNode)y.p).left == z) ((BinaryTreeNode)y.p).left = y; else ((BinaryTreeNode)y.p).right = y; } if(y.left != NIL) y.left.p = y; if(y.right != NIL) y.right.p = y; if(x.p == z) x.p = y; } z.p = NIL; z.left = (BinaryTreeNode)NIL; z.left = (BinaryTreeNode)NIL; if(delfix) deleteFixup((RedBlackNode)x); changed(); } private void deleteFixup(RedBlackNode x) { RedBlackNode w; while(root != x && x.color == BLACK) { if(x == (RedBlackNode)((BinaryTreeNode)x.p).left) { w = (RedBlackNode)((BinaryTreeNode)x.p).right; if(w.color == RED) { w.color = BLACK; ((RedBlackNode)x.p).color = RED; leftRotate((BinaryTreeNode)x.p); w = (RedBlackNode)((BinaryTreeNode)x.p).right; } if(((RedBlackNode)w.left).color == BLACK && ((RedBlackNode)w.right).color == BLACK) { w.color = RED; x = (RedBlackNode)x.p; } else { if(((RedBlackNode)w.right).color == BLACK) { ((RedBlackNode)w.left).color = BLACK; w.color = RED; rightRotate(w); w = (RedBlackNode)((BinaryTreeNode)x.p).right; } w.color = ((RedBlackNode)x.p).color; ((RedBlackNode)x.p).color = BLACK; ((RedBlackNode)w.right).color = BLACK; leftRotate((BinaryTreeNode)x.p); x = (RedBlackNode)root; } } else { w = (RedBlackNode)((BinaryTreeNode)x.p).left; if(w.color == RED) { w.color = BLACK; ((RedBlackNode)x.p).color = RED; rightRotate((BinaryTreeNode)x.p); w = (RedBlackNode)((BinaryTreeNode)x.p).left; } if(((RedBlackNode)w.right).color == BLACK && ((RedBlackNode)w.left).color == BLACK) { w.color = RED; x = (RedBlackNode)x.p; } else { if(((RedBlackNode)w.left).color == BLACK) { ((RedBlackNode)w.right).color = BLACK; w.color = RED; leftRotate(w); w = (RedBlackNode)((BinaryTreeNode)x.p).left; } w.color = ((RedBlackNode)x.p).color; ((RedBlackNode)x.p).color = BLACK; ((RedBlackNode)w.left).color = BLACK; rightRotate((BinaryTreeNode)x.p); x = (RedBlackNode)root; } } } x.color = BLACK; } private void leftRotate(BinaryTreeNode x) { BinaryTreeNode y = x.right; x.right = y.left; if(y.left != NIL) y.left.p = x; if(y != NIL) y.p = x.p; if(x.p == NIL) root = y; else if(x == ((BinaryTreeNode)x.p).left) ((BinaryTreeNode)x.p).left = y; else ((BinaryTreeNode)x.p).right = y; y.left = x; if(x != NIL) x.p = y; } private void rightRotate(BinaryTreeNode x) { BinaryTreeNode y = x.left; x.left = y.right; if(y.right != NIL) y.right.p = x; if(y != NIL) y.p = x.p; if(x.p == NIL) root = y; else { if(x == ((BinaryTreeNode)x.p).right) ((BinaryTreeNode)x.p).right = y; else ((BinaryTreeNode)x.p).left = y; } y.right = x; if(x != NIL) x.p = y; } private int blackHeight(RedBlackNode node, int height) { if(node == NIL) return height; return blackHeight((RedBlackNode)node.p, node.color == BLACK ? height + 1 : height); } protected String verify() { String result = super.verify(); // check sentinel if(((RedBlackNode)NIL).color != BLACK) { System.out.println("Color of NIL has changed"); error(); } // red-black properties // 1. every node is either red or black // -> ensured by the boolean color var // 2. Every leaf (NIL) is black if(((RedBlackNode)NIL).color != BLACK) { System.out.println("2. Every leaf (NIL) is black - violated"); error(); } // 3. If a node is red, then both its child are black inorderWalk(root, new TreeWalk() { public void node(TreeNode node_, Object misc) { RedBlackNode node = (RedBlackNode)node_; if(node.color == RED) { if(((RedBlackNode)node.left).color != BLACK) { System.out.println("3. If a node is red, " + "then both its child are black - violated (left)"); error(); } if(((RedBlackNode)node.right).color != BLACK) { System.out.println("3. If a node is red, " + "then both its child are black - violated (right)"); error(); } } } }, null); // 4. Every simple path from a node to a descendant leaf contains the same // number of black nodes inorderWalk(root, new TreeWalk() { int blackHeight = -1; private void updateBH(RedBlackNode node) { int bh = blackHeight(node, 1); if(blackHeight == -1) blackHeight = bh; else if(bh != blackHeight) { System.out.println("4. Every simple path from a node to a " + "descendant leaf contains the same number " + "of black nodes - violated"); error(); } } public void node(TreeNode node_, Object misc) { RedBlackNode node = (RedBlackNode)node_; if(node.left == NIL) updateBH(node); if(node.right == NIL) updateBH(node); } }, null); return result + "(RBT,OK)"; } protected BinaryTreeNode newTestNode(long key) { return new RedBlackNode(key, null); } public static void main(String[] argv) { test(Integer.parseInt(argv[0]), Integer.parseInt(argv[1]), new RedBlackTree()); } } /* $Log: RedBlackTree.java,v $ Revision 1.1 2002/07/11 12:00:11 ohitz Initial checkin Revision 1.2 2001/01/04 16:28:42 schubige Header update for 2001 and DIUF Revision 1.1 1999/10/07 11:02:12 schubige Added red black and binary tree classes */