/* Copyright (c) 2008 Derrick Coetzee * http://en.literateprograms.org/Red-black_tree_(C)?oldid=7982 * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "rbtree.h" #include #ifndef NULL # define NULL ((void*)0) #endif typedef rbtree_node node; typedef enum rbtree_node_color color; static node grandparent(node n); static node sibling(node n); static node uncle(node n); static void verify_properties(rbtree t); static void verify_property_1(node root); /* static void verify_property_2(node root); */ static color node_color(node n); static void verify_property_4(node root); /* static void verify_property_5(node root); */ static void verify_property_5_helper(node n, int black_count, int* black_count_path); static node lookup_node(rbtree t, void* key); static void rotate_left(rbtree t, node n); static void rotate_right(rbtree t, node n); static void replace_node(rbtree t, node oldn, node newn); static void insert_case1(rbtree t, node n); static void insert_case2(rbtree t, node n); static void insert_case3(rbtree t, node n); static void insert_case4(rbtree t, node n); static void insert_case5(rbtree t, node n); static node maximum_node(node root); static void delete_case1(rbtree t, node n); static void delete_case2(rbtree t, node n); static void delete_case3(rbtree t, node n); static void delete_case4(rbtree t, node n); static void delete_case5(rbtree t, node n); static void delete_case6(rbtree t, node n); node grandparent(node n) { assert (n != NULL); assert (n->parent != NULL); /* Not the root node */ assert (n->parent->parent != NULL); /* Not child of root */ return n->parent->parent; } node sibling(node n) { assert (n != NULL); assert (n->parent != NULL); /* Root node has no sibling */ if (n == n->parent->left) return n->parent->right; else return n->parent->left; } node uncle(node n) { assert (n != NULL); assert (n->parent != NULL); /* Root node has no uncle */ assert (n->parent->parent != NULL); /* Children of root have no uncle */ return sibling(n->parent); } void verify_properties(rbtree t) { #ifdef VERIFY_RBTREE verify_property_1(t->root); verify_property_2(t->root); /* Property 3 is implicit */ verify_property_4(t->root); verify_property_5(t->root); #endif } void verify_property_1(node n) { assert(node_color(n) == RED || node_color(n) == BLACK); if (n == NULL) return; verify_property_1(n->left); verify_property_1(n->right); } /* void verify_property_2(node root) { assert(node_color(root) == BLACK); } */ color node_color(node n) { return n == NULL ? BLACK : n->color; } void verify_property_4(node n) { if (node_color(n) == RED) { assert (node_color(n->left) == BLACK); assert (node_color(n->right) == BLACK); assert (node_color(n->parent) == BLACK); } if (n == NULL) return; verify_property_4(n->left); verify_property_4(n->right); } /* void verify_property_5(node root) { int black_count_path = -1; verify_property_5_helper(root, 0, &black_count_path); } */ void verify_property_5_helper(node n, int black_count, int* path_black_count) { if (node_color(n) == BLACK) { black_count++; } if (n == NULL) { if (*path_black_count == -1) { *path_black_count = black_count; } else { assert (black_count == *path_black_count); } return; } verify_property_5_helper(n->left, black_count, path_black_count); verify_property_5_helper(n->right, black_count, path_black_count); } void rbtree_init(rbtree t, rbtree_compare_func compare) { t->root = NULL; t->compare = compare; verify_properties(t); } node lookup_node(rbtree t, void* key) { node n = t->root; while (n != NULL) { int comp_result = t->compare(key, n->key); if (comp_result == 0) { return n; } else if (comp_result < 0) { n = n->left; } else { assert(comp_result > 0); n = n->right; } } return n; } void* rbtree_lookup(rbtree t, void* key) { node n = lookup_node(t, key); return n == NULL ? NULL : n->value; } void rotate_left(rbtree t, node n) { node r = n->right; replace_node(t, n, r); n->right = r->left; if (r->left != NULL) { r->left->parent = n; } r->left = n; n->parent = r; } void rotate_right(rbtree t, node n) { node L = n->left; replace_node(t, n, L); n->left = L->right; if (L->right != NULL) { L->right->parent = n; } L->right = n; n->parent = L; } void replace_node(rbtree t, node oldn, node newn) { if (oldn->parent == NULL) { t->root = newn; } else { if (oldn == oldn->parent->left) oldn->parent->left = newn; else oldn->parent->right = newn; } if (newn != NULL) { newn->parent = oldn->parent; } } void rbtree_insert(rbtree t, rbtree_node inserted_node) { inserted_node->color = RED; inserted_node->left = NULL; inserted_node->right = NULL; inserted_node->parent = NULL; if (t->root == NULL) { t->root = inserted_node; } else { node n = t->root; while (1) { int comp_result = t->compare(inserted_node->key, n->key); if (comp_result == 0) { n->value = inserted_node->value; return; } else if (comp_result < 0) { if (n->left == NULL) { n->left = inserted_node; break; } else { n = n->left; } } else { assert (comp_result > 0); if (n->right == NULL) { n->right = inserted_node; break; } else { n = n->right; } } } inserted_node->parent = n; } insert_case1(t, inserted_node); verify_properties(t); } void insert_case1(rbtree t, node n) { if (n->parent == NULL) n->color = BLACK; else insert_case2(t, n); } void insert_case2(rbtree t, node n) { if (node_color(n->parent) == BLACK) return; /* Tree is still valid */ else insert_case3(t, n); } void insert_case3(rbtree t, node n) { if (node_color(uncle(n)) == RED) { n->parent->color = BLACK; uncle(n)->color = BLACK; grandparent(n)->color = RED; insert_case1(t, grandparent(n)); } else { insert_case4(t, n); } } void insert_case4(rbtree t, node n) { if (n == n->parent->right && n->parent == grandparent(n)->left) { rotate_left(t, n->parent); n = n->left; } else if (n == n->parent->left && n->parent == grandparent(n)->right) { rotate_right(t, n->parent); n = n->right; } insert_case5(t, n); } void insert_case5(rbtree t, node n) { n->parent->color = BLACK; grandparent(n)->color = RED; if (n == n->parent->left && n->parent == grandparent(n)->left) { rotate_right(t, grandparent(n)); } else { assert (n == n->parent->right && n->parent == grandparent(n)->right); rotate_left(t, grandparent(n)); } } rbtree_node rbtree_delete(rbtree t, void* key) { node child; node n = lookup_node(t, key); if (n == NULL) return NULL; /* Key not found, do nothing */ if (n->left != NULL && n->right != NULL) { /* Copy key/value from predecessor and then delete it instead */ node pred = maximum_node(n->left); n->key = pred->key; n->value = pred->value; n = pred; } assert(n->left == NULL || n->right == NULL); child = n->right == NULL ? n->left : n->right; if (node_color(n) == BLACK) { n->color = node_color(child); delete_case1(t, n); } replace_node(t, n, child); verify_properties(t); return n; } static node maximum_node(node n) { assert (n != NULL); while (n->right != NULL) { n = n->right; } return n; } void delete_case1(rbtree t, node n) { if (n->parent == NULL) return; else delete_case2(t, n); } void delete_case2(rbtree t, node n) { if (node_color(sibling(n)) == RED) { n->parent->color = RED; sibling(n)->color = BLACK; if (n == n->parent->left) rotate_left(t, n->parent); else rotate_right(t, n->parent); } delete_case3(t, n); } void delete_case3(rbtree t, node n) { if (node_color(n->parent) == BLACK && node_color(sibling(n)) == BLACK && node_color(sibling(n)->left) == BLACK && node_color(sibling(n)->right) == BLACK) { sibling(n)->color = RED; delete_case1(t, n->parent); } else delete_case4(t, n); } void delete_case4(rbtree t, node n) { if (node_color(n->parent) == RED && node_color(sibling(n)) == BLACK && node_color(sibling(n)->left) == BLACK && node_color(sibling(n)->right) == BLACK) { sibling(n)->color = RED; n->parent->color = BLACK; } else delete_case5(t, n); } void delete_case5(rbtree t, node n) { if (n == n->parent->left && node_color(sibling(n)) == BLACK && node_color(sibling(n)->left) == RED && node_color(sibling(n)->right) == BLACK) { sibling(n)->color = RED; sibling(n)->left->color = BLACK; rotate_right(t, sibling(n)); } else if (n == n->parent->right && node_color(sibling(n)) == BLACK && node_color(sibling(n)->right) == RED && node_color(sibling(n)->left) == BLACK) { sibling(n)->color = RED; sibling(n)->right->color = BLACK; rotate_left(t, sibling(n)); } delete_case6(t, n); } void delete_case6(rbtree t, node n) { sibling(n)->color = node_color(n->parent); n->parent->color = BLACK; if (n == n->parent->left) { assert (node_color(sibling(n)->right) == RED); sibling(n)->right->color = BLACK; rotate_left(t, n->parent); } else { assert (node_color(sibling(n)->left) == RED); sibling(n)->left->color = BLACK; rotate_right(t, n->parent); } }