// Computer Science 367, Section 3, Fall 1997 // Instructor: Michael Siff (siff@cs.wisc.edu) // // // FILE: red-black.C // // // A red-black tree class template implemented as a derived class of the // binary search tree class template (which is implemented using the binary // tree class template). // // INVARIANT for RBT: // An RBT is a binary search tree so it satisfies the binary search tree // property: For a given node, its key is greater than all the keys // appearing in its left subtree and less than all the keys appearing in // its right subtree. // // and the red-black properties: // 0. Every node is either red or black. // 1. Every external leaf (NULL node) is considered to be black. // 2. If a node is red, then both its children are black. // 3. For a given node, the number of black nodes between it and a NULL // node descendant is the same regardless of which path is taken. // PRIVATE MEMBER FUNCTIONS (utilities) // ------------------------ template Item RBT::itemOf(const pair,Key>& ick) const // Overrides the BST itemOf { return ick.first.first; } template color RBT::colorOf(BinaryTree,Key> >*node) const // NULL nodes are considered to be black { color result = BLACK; if (node != NULL) result = (node->valOf()).first.second; return result; } template void RBT::setColor(BinaryTree,Key> > *node, color c) // Precondition: node is not NULL or c is black { assert(node!=NULL || c==BLACK); if (node != NULL) { pair,Key> ick = node->valOf(); ick.first.second = c; node->setVal(ick); } } template BinaryTree,Key> > *RBT::rotateLeft(BinaryTree,Key> > *x) // This code is based on that appearing in _Introduction to Algorithms_ // by Cormen, Leiserson and Rivest, p 266. // (x) (y) // / \ / \ // 'a (y) ===> (x) 'c // / \ / \ // 'b 'c 'a 'b // Returns a pointer to the resulting node y { BT *y = NULL; if (x != NULL) { y = x->rightOf(); if (y != NULL) { BT *beta = y->leftOf(); if (x == root) { BT *gamma = y->rightOf(); root = new BT(y->valOf()); root->setLeft(x); root->setRight(gamma); x->setRight(beta); y->setLeft(NULL); y->setRight(NULL); delete y; y = root; } else { BT *p = x->parentOf(); if (isRightChild(x)) p->setRight(y); else p->setLeft(y); y->setLeft(x); x->setRight(beta); } } } return y; } template BinaryTree,Key> > *RBT::rotateRight(BinaryTree,Key> > *y) // (y) (x) // / \ / \ // (x) 'c ===> 'a (y) // / \ / \ // 'a 'b 'b 'c // Returns a pointer to the resulting node x { BT *x = NULL; if (y!= NULL) { x = y->leftOf(); if (x != NULL) { BT *beta = x->rightOf(); if (y == root) { BT *alpha = x->leftOf(); root = new BT(x->valOf()); root->setRight(y); root->setLeft(alpha); y->setLeft(beta); x->setLeft(NULL); x->setRight(NULL); delete x; x = root; } else { BT *p = y->parentOf(); if (isRightChild(y)) p->setRight(x); else p->setLeft(x); x->setRight(y); y->setLeft(beta); } } } return x; } template void RBT::fixInsert(BinaryTree,Key> > *x) // Precondition: node is not NULL // This code is based on that appearing in _Introduction to Algorithms_ // by Cormen, Leiserson and Rivest, p 268. { if (x != root) { for (BT *p = x->parentOf(); p != root && colorOf(p) == RED; p = x->parentOf()) { if (!isRightChild(p)) { // Left case: x's parent is a left child BT *pp = p->parentOf(); BT *uncle = pp->rightOf(); if (colorOf(uncle)==RED) { // case 1: x's uncle is red: recolor // (Cb) x(Cr) // / \ / \ // (Br) (Dr) (Bb) (Db) // / \ / \ ===> / \ / \ // x(Ar) 'c 'd 'e (Ar) 'c 'd 'e // / \ / \ // 'a 'b 'a 'b // // (or symmetrical case where x is a right child) setColor(p, BLACK); setColor(uncle, BLACK); setColor(pp, RED); x = pp; } else { if (isRightChild(x)) { // case 2: x is a right child: rotate to get to case 3 x = p; rotateLeft(p); p = x->parentOf(); // now x is a left child } // case 3: x is a left child: recolor and rotate grandparent setColor(p, BLACK); pp = p->parentOf(); setColor(pp, RED); p = rotateRight(pp); } } else { // Right case: x's parent is a right child // symmetric with left case BT *pp = p->parentOf(); BT *uncle = pp->leftOf(); if (colorOf(uncle)==RED) { // case 1: x's uncle is red: recolor setColor(p, BLACK); setColor(uncle, BLACK); setColor(pp, RED); x = pp; } else { // case 2: x is a left child: rotate to get to case 3 if (!isRightChild(x)) { x = p; rotateRight(p); p = x->parentOf(); } // case 3: x is a right child: recolor and rotate grandparent setColor(p, BLACK); pp = p->parentOf(); setColor(pp, RED); p = rotateLeft(pp); } } } } setColor(root, BLACK); } template void RBT::fixRemove(BinaryTree,Key> > *x, BinaryTree,Key> > *p) // Precondition: p is the parent of the node just deleted. If x is not NULL // then x is the child of p. // This code is based on that appearing in _Introduction to Algorithms_ // by Cormen, Leiserson and Rivest, p 274. { while(x != root && colorOf(x) == BLACK) { if (p->leftOf() == x) { // Left case: x is (or was if it has been deleted) a left child BT *sibling = p->rightOf(); if (colorOf(sibling) == RED) { // case 1: sibling is RED: recolor and rotate parent setColor(sibling, BLACK); setColor(p, RED); rotateLeft(p); sibling = p->rightOf(); } if (colorOf(sibling->leftOf()) == BLACK && colorOf(sibling->rightOf()) == BLACK) { // case 2: sibling's children are both BLACK: recolor and move up setColor(sibling, RED); x = p; p = p->parentOf(); } else { if (colorOf(sibling->rightOf()) == BLACK) { // case 3: sibling's right child is BLACK: recolor and rotate to // get to case 4 setColor(sibling->leftOf(), BLACK); setColor(sibling, RED); rotateRight(sibling); sibling = p->rightOf(); // sibling's right child is now RED } // case 3: sibling's right child is RED: recolor, rotate parent, stop setColor(sibling, colorOf(p)); setColor(p, BLACK); setColor(sibling->rightOf(), BLACK); rotateLeft(p); x = root; // signal to halt loop } } else { // Right case: x is (or was if it has been deleted) a right child // symmetric with left case BT *sibling = p->leftOf(); if (colorOf(sibling) == RED) { setColor(sibling, BLACK); setColor(p, RED); rotateRight(p); sibling = p->leftOf(); } if (colorOf(sibling->leftOf()) == BLACK && colorOf(sibling->rightOf()) == BLACK) { setColor(sibling, RED); x = p; p = p->parentOf(); } else { if (colorOf(sibling->leftOf()) == BLACK) { setColor(sibling->rightOf(), BLACK); setColor(sibling, RED); rotateLeft(sibling); sibling = p->leftOf(); } setColor(sibling, colorOf(p)); setColor(p, BLACK); setColor(sibling->leftOf(), BLACK); rotateRight(p); x = root; // signal to halt loop } } } setColor(x, BLACK); } // Constructors // ------------ template RBT::RBT() // create an empty tree - relies on superclass' default constructor {} template RBT::RBT(const RBT& source) : BST,Key>(source) // copy constructor {} // Destructor // ---------- template RBT::~RBT() // relies on superclass' destructor {} // Constant Member Functions // ------------------------- template bool RBT::search(const Key& k, Item& returnVal) const { BT *node = _search(root, k); if (node != NULL) returnVal = itemOf(node->valOf()); return(node != NULL); } // Modification Member Functions // ----------------------------- template bool RBT::insert(const Item& v, const Key& k) { BT *node = _insert(pair,Key>(pair(v, RED), k)); if (node != NULL) fixInsert(node); return (node != NULL); } template bool RBT::remove(const Key& k) { BT *node = _search(root, k); if (node != NULL) { color c = colorOf(node); BT *p = node->parentOf(); BT *x; // there are two cases: // (0) if node has at most one child, move its child (if it has one) up // and delete node if (node->leftOf() == NULL || node->rightOf() == NULL) x = removeNode(node); // (1) if node has two children, // let q = node's successor, copy q's value to node, and delete q. // Note this works because q can have at most one child. else { BT *q = successor(node); p = q->parentOf(); node->setVal(q->valOf()); x = removeNode(q); } if (c==BLACK) fixRemove(x,p); } return (node != NULL); }