/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: t; c-basic-offset: 3 -*- */ /*================================================================ * * Project : Freyja * Author : Mongoose * Website : http://gooseegg.sourceforge.net/ * Email : mongoose@users.sourceforge.net * Object : Tree * License : GPL See file COPYING, also (C) 2000 Mongoose * Comments: Template tree class, which is also the iterator * * * Red-Black trees are a type of binary search trees * with the properities: * * 1. Every node is red or black. * 2. The root node must be black. * 3. Every leaf node is black. (null pointers) * 4. If a node is red, then both its children are black. * 5. Every simple path from a node to a descendant * leaf contains the same number of black nodes. * 6. Any path from the root to a leaf must not have * adjacent red nodes. * * * This file was generated using Mongoose's C++ * template generator script. * *-- History ------------------------------------------------ * * 2002.02.17: * Mongoose - Rewritten as a Red-Black tree * * 2002.02.16: * Mongoose - Dug out of cobwebs and fixed up * Yes, I believe in code reuse! =) * * 2000.10.26: * Mongoose - Created ================================================================*/ #ifndef _TREE_H_ #define _TREE_H_ #include #include #ifdef USE_IOSTREAM #include #endif #ifdef DEBUG_MEMORY #include #endif typedef enum { _tree_h_black, _tree_h_red } _tree_h_color_t; template class TreeNode { public: TreeNode(Key key, Data data) { SetColor(_tree_h_red); SetData(data); SetKey(key); SetParent(NULL); SetLeft(NULL); SetRight(NULL); } ~TreeNode() { TreeNode *left; TreeNode *right; left = GetLeft(); right = GetRight(); SetParent(NULL); SetLeft(NULL); SetRight(NULL); if (left) { left->SetParent(NULL); delete left; } if (right) { right->SetParent(NULL); delete right; } } /// Color ///////////////////////////////////// void SetColor(_tree_h_color_t color) { _color = color; } _tree_h_color_t GetColor() { return _color; } /// Left, child /////////////////////////////// TreeNode *GetChild() { return GetLeft(); } void SetChild(TreeNode *tree) { Left(tree); } TreeNode *GetLeft() { return _left; } void SetLeft(TreeNode *tree) { if (tree == this) { return; } _left = tree; if (tree) { tree->SetParent(this); } } /// Right, sibling /////////////////////////// TreeNode *GetSibling() { return GetRight(); } void SetSibling(TreeNode *tree) { SetRight(tree); } TreeNode *GetRight() { return _right; } void SetRight(TreeNode *tree) { if (tree == this) { return; } _right = tree; if (tree) { tree->SetParent(this); } } /// Data ////////////////////////////////////// Data GetData() { return _data; } void SetData(Data data) { _data = data; } /// Key //////////////////////////////////////// Key GetKey() { return _key; } void SetKey(Key key) { _key = key; } /// Parent ///////////////////////////////////// TreeNode *GetParent() { return _parent; } void SetParent(TreeNode *parent) { _parent = parent; } /// Misc /////////////////////////////////////// #ifdef USE_IOSTREAM void PrintNode() { cout << "(" << _key << ", " << _data << ", " << ((GetColor() == _tree_h_red) ? "Red" : "Black") << ")"; } void PrintInorder() { if (_left) { _left->PrintInorder(); //cout << ", "; cout << endl; } PrintNode(); if (_right) { //cout << ", "; cout << endl; _right->PrintInorder(); } } #endif void PrintNodeSpecial(void (*print_func_k)(Key), void (*print_func_d)(Data)) { printf("("); if (print_func_k) (*print_func_k)(_key); printf(", "); if (print_func_d) (*print_func_d)(_data); printf(", %s)", ((GetColor() == _tree_h_red) ? "Red" : "Black")); } void PrintInorderSpecial(void (*print_func_k)(Key), void (*print_func_d)(Data)) { if (_left) { _left->PrintInorderSpecial(print_func_k, print_func_d); printf(",\n"); // printf(", "); } PrintNodeSpecial(print_func_k, print_func_d); if (_right) { printf(",\n"); // printf(", "); _right->PrintInorderSpecial(print_func_k, print_func_d); } } TreeNode *SearchByData(Data data, bool *error) { TreeNode *tree = NULL; *error = true; if (_data == data) { *error = false; return this; } if (_left) { tree = _left->SearchByData(data, error); } if (_right && !tree) { tree = _right->SearchByData(data, error); } return tree; } TreeNode *SearchByKey(Key key, bool *error) { *error = false; if (_key == key) { return this; } else if (_left && key < _key) { return _left->SearchByKey(key, error); } else if (_right) { return _right->SearchByKey(key, error); } else { *error = true; return 0; //NULL; } } void Insert(TreeNode *tree) { if (!tree || tree == this) { return; } if (tree->GetKey() < _key) { if (!_left) { SetLeft(tree); } else { _left->Insert(tree); } } else { if (!_right) { SetRight(tree); } else { _right->Insert(tree); } } } private: _tree_h_color_t _color; /* Color of tree node */ Key _key; /* Unique identifer? */ Data _data; /* Data for this tree */ TreeNode *_left; /* Left or child node */ TreeNode *_right; /* Right or sibling node */ TreeNode *_parent; /* Parent of the tree node */ }; //////////////////////////////////////////////////////////////// // Iterator //////////////////////////////////////////////////////////////// template class Tree { public: Tree() { _error = false; _num_elements = 0; _root = 0; } ~Tree() { Clear(); } unsigned int NumElements() { return _num_elements; } Data SearchByKey(Key key, bool *error) { TreeNode *seeking; *error = true; // Mongoose 2002.02.16, Nothing to search if (!_root) { return 0; } seeking = _root->SearchByKey(key, error); if (seeking) { return seeking->GetData(); } return 0; } Key SearchByData(Data data, bool *error) { TreeNode *seeking; *error = true; // Mongoose 2002.02.16, Nothing to search if (!_root) { return 0; } seeking = _root->SearchByData(data, error); if (seeking) { return seeking->GetKey(); } return 0; } void Insert(Key key, Data data) { TreeNode *tree; tree = new TreeNode(key, data); ++_num_elements; if (_root) { _root->Insert(tree); RestoreRedBlackAfterInsert(tree); } else { _root = tree; _root->SetColor(_tree_h_black); } } bool RemoveByData(Data data) { bool error; if (_root) { Remove(_root->SearchByData(data, &error)); } return error; } bool RemoveByKey(Key key) { bool error; if (_root) { #ifdef OBSOLETE // Mongoose 2002.02.18, To remove duplicates erorr = false; while (!error) { #endif Remove(_root->SearchByKey(key, &error)); #ifdef OBSOLETE } #endif } return error; } void Erase() { Clear(); } void Clear() { if (_root) { delete _root; } _num_elements = 0; _error = false; _root = 0; } /// Misc ////////////////////////////////////// Data operator [] (Key key) { _error = false; if (_root) { return SearchByKey(key, &_error); } _error = true; return 0; } #ifdef USE_IOSTREAM void PrintTree(TreeNode *tree, unsigned int height, unsigned int seek, bool rightmost) { TreeNode *left, *right, *parent; if (!tree) { return; } parent = tree->GetParent(); if (height == seek) { if (!parent) { cout << endl << "[height " << height << "] " << endl; if (tree->GetColor() == _tree_h_red) { cout << "*"; } } else { if (parent->GetColor() == _tree_h_red && tree->GetColor() == _tree_h_red) { cout << "*"; } } cout << "(" << tree->GetKey() << ", " << ((tree->GetColor() == _tree_h_red) ? "red" : "blk") << ")"; if (rightmost) { cout << endl << "[height " << (height+1) << "] " << endl; PrintTree(_root, 0, ++seek, true); } else { cout << " "; } return; } else if (seek < height) { return; } left = tree->GetLeft(); right = tree->GetRight(); ++height; if (left) { PrintTree(left, height, seek, false); } else { cout << "(-, blk) "; } if (right) { PrintTree(right, height, seek, rightmost); } else { cout << "(-, blk) "; } if (parent) { if (parent->GetRight() != tree) { cout << " | "; } } } void PrintAsTree() { PrintTree(_root, 0, 0, true); cout << endl << "Nodes marked with * are in error" << endl; } void Print() { cout << "Tree: " << _num_elements <<" elements {" << endl; if (_root) { cout << "Root: "; _root->PrintNode(); cout << endl; _root->PrintInorder(); } cout << endl << "}" << endl; } #endif void PrintSpecial(void (*print_func_k)(Key), void (*print_func_d)(Data)) { printf("Tree: %i elements {\n", _num_elements); if (_root && print_func_k && print_func_d) { printf("Root: "); _root->PrintNodeSpecial(print_func_k, print_func_d); printf("\n"); _root->PrintInorderSpecial(print_func_k, print_func_d); } printf("\n}\n"); } Key Root() { if (_root) { return _root->GetKey(); } return 0; } bool Error() { return _error; } bool IsValidRedBlackTree() { return IsValidRedBlackTreeCheck(_root, true); } private: TreeNode *GetSuccessor(TreeNode *tree) { TreeNode *successor; successor = tree->GetRight(); if (successor) { while (successor->GetLeft()) { successor = successor->GetLeft(); } return successor; } else { successor = tree->GetParent(); while (tree == successor->GetRight()) { tree = successor; successor = successor->GetParent(); } if (successor == _root) { return NULL; } return successor; } } TreeNode *GetPredecessor(TreeNode *tree) { TreeNode *predecessor; predecessor = tree->GetLeft(); if (predecessor) { while (predecessor->GetRight()) { predecessor = predecessor->GetRight(); } return predecessor; } else { predecessor = tree->GetParent(); while (tree == predecessor->GetLeft()) { if (predecessor == _root) { return NULL; } tree = predecessor; predecessor = predecessor->GetParent(); } return predecessor; } } bool IsValidRedBlackTreeCheck(TreeNode *current, bool valid) { TreeNode *right, *left; _tree_h_color_t color_red; if (!current) { return valid; } // Mongoose 2002.02.19, Check for a red root if (!current->GetParent() && current->GetColor() == _tree_h_red) { return false; } color_red = (current->GetColor() == _tree_h_red); left = current->GetLeft(); right = current->GetRight(); // Mongoose 2002.02.19, Check for adj red nodes if (left) { if (color_red && left->GetColor() == _tree_h_red) { return false; } if (!IsValidRedBlackTreeCheck(left, valid)) return false; } if (right) { if (color_red && right->GetColor() == _tree_h_red) { return false; } if (!IsValidRedBlackTreeCheck(right, valid)) return false; } return true; } void RotateLeft(TreeNode *tree) { TreeNode *right, *right_leftchild, *parent, *uncle; if (!tree || !_root) { return; } // Get tree's right node right = tree->GetRight(); // Get right node's left child right_leftchild = NULL; if (right) { right_leftchild = right->GetLeft(); } // Set tree's right node to right's left child tree->SetRight(right_leftchild); // Child now has a new parent if (right_leftchild) { right_leftchild->SetParent(tree); } // Right also has a new parent if (right) { right->SetParent(tree->GetParent()); } // Get parent parent = tree->GetParent(); if (parent) // Not root { uncle = parent->GetLeft(); // Mix up at hosptial, switch parent's children! if (tree == uncle) { parent->SetLeft(right); } else { parent->SetRight(right); } } else // TreeNode 'tree' was root, so now right is root { _root = right; } if (right) { // TreeNode 'tree' is now right's left child right->SetLeft(tree); if (tree) { tree->SetParent(right); } } } void RotateRight(TreeNode *tree) { TreeNode *left, *left_rightchild, *parent, *uncle; if (!tree || !_root) { return; } left = tree->GetLeft(); left_rightchild = NULL; if (left) { left_rightchild = left->GetRight(); } tree->SetLeft(left_rightchild); if (left_rightchild) { left_rightchild->SetParent(tree); } if (left) { left->SetParent(tree->GetParent()); } parent = tree->GetParent(); if (parent) //if node is not the root { uncle = parent->GetRight(); if (tree == uncle) { parent->SetRight(left); } else { parent->SetLeft(left); } } else { _root = left; } left->SetRight(tree); if (tree) { tree->SetParent(left); } } void TreeNodeShallowCopy(TreeNode *src, TreeNode *dest, bool no_links) { if (!src || !dest) { return; } dest->SetKey(src->GetKey()); dest->SetData(src->GetData()); dest->SetColor(src->GetColor()); if (!no_links) { dest->SetRight(src->GetRight()); dest->SetLeft(src->GetLeft()); dest->SetParent(src->GetParent()); } } void Remove(TreeNode *tree) { TreeNode *left, *right, *parent, *prev, *cur; // Mongoose 2002.02.16, Nothing to remove if (!tree || !_root) { return; } left = tree->GetLeft(); right = tree->GetRight(); parent = tree->GetParent(); if (!left || !right) { prev = tree; } else { prev = GetSuccessor(tree); } if (prev->GetLeft()) { cur = prev->GetLeft(); } else { cur = prev->GetRight(); } if (cur) { cur->SetParent(prev->GetParent()); } if (!prev->GetParent()) { _root = cur; } else { parent = prev->GetParent(); if (prev == parent->GetLeft()) { parent->SetLeft(cur); } else { parent->SetRight(cur); } } if (prev != tree) { TreeNodeShallowCopy(prev, tree, true); if (prev->GetParent()) { if (prev == (prev->GetParent())->GetLeft()) (prev->GetParent())->SetLeft(tree); else if (prev == (prev->GetParent())->GetRight()) (prev->GetParent())->SetRight(tree); } } --_num_elements; if (prev) { prev->SetRight(NULL); prev->SetParent(NULL); prev->SetLeft(NULL); delete prev; } if (tree->GetColor() == _tree_h_black) { RestoreRedBlackAfterRemove(cur); } } void RestoreRedBlackAfterRemove(TreeNode *tree) { TreeNode *parent, *sibling, *sleft, *sright; if (!tree || !_root) { return; } parent = tree->GetParent(); while ((tree != _root) && (parent->GetColor() == _tree_h_black)) { if (tree == parent->GetLeft()) { sibling = parent->GetRight(); if (sibling && sibling->GetColor() == _tree_h_red) { sibling->SetColor(_tree_h_black); parent->SetColor(_tree_h_red); RotateLeft(parent); sibling = parent->GetRight(); } if (sibling) { sleft = sibling->GetLeft(); sright = sibling->GetRight(); } else { sleft = sright = NULL; } if (sright && sright->GetColor() == _tree_h_black && sleft && sleft->GetColor() ==_tree_h_black) { sibling->SetColor(_tree_h_red); tree = parent; } else { if (sright && sright->GetColor() == _tree_h_black) { sibling->SetColor(_tree_h_red); sleft->SetColor(_tree_h_black); RotateRight(sibling); sibling = parent->GetRight(); } sibling->SetColor(parent->GetColor()); parent->SetColor(_tree_h_black); sright->SetColor(_tree_h_black); RotateLeft(parent); tree = _root; } } else { sibling = parent->GetLeft(); if (sibling && sibling->GetColor() == _tree_h_red) { sibling->SetColor(_tree_h_black); parent->SetColor(_tree_h_red); RotateLeft(parent); sibling = parent->GetLeft(); } if (sibling) { sleft = sibling->GetLeft(); sright = sibling->GetRight(); } else { sleft = sright = NULL; } if (sright && sright->GetColor() == _tree_h_black && sleft && sleft->GetColor() ==_tree_h_black) { sibling->SetColor(_tree_h_red); tree = parent; } else { if (sleft && sleft->GetColor() == _tree_h_black) { sibling->SetColor(_tree_h_red); sright->SetColor(_tree_h_black); RotateLeft(sibling); sibling = parent->GetLeft(); } sibling->SetColor(parent->GetColor()); parent->SetColor(_tree_h_black); sleft->SetColor(_tree_h_black); RotateRight(parent); tree = _root; } } parent = tree->GetParent(); } tree->SetColor(_tree_h_black); } void RestoreRedBlackAfterInsert(TreeNode *tree) { TreeNode *parent, *grandparent, *uncle; if (!tree || !_root || tree == _root) { return; } tree->SetColor(_tree_h_red); parent = tree->GetParent(); while ((tree != _root) && (parent->GetColor() == _tree_h_red)) { grandparent = parent->GetParent(); if (parent == grandparent->GetLeft()) { uncle = grandparent->GetRight(); if (uncle && uncle->GetColor() == _tree_h_red) { // Case 1 - Change the colors parent->SetColor(_tree_h_black); uncle->SetColor(_tree_h_black); grandparent->SetColor(_tree_h_red); // Move up the tree tree = grandparent; } else // Uncle is a black node { if (tree == parent->GetRight()) { // Case 2 - Move up and rotate tree = parent; RotateLeft(tree); } // Case 3 - Make no changes to _root tree // Change colors for Case 2 / Case 3 parent->SetColor(_tree_h_black); grandparent->SetColor(_tree_h_red); RotateRight(grandparent); } } else // TreeNode 'tree' is in right subtree { uncle = grandparent->GetLeft(); if (uncle && uncle->GetColor() == _tree_h_red) { // Case 1 - Change the colors parent->SetColor(_tree_h_black); uncle->SetColor(_tree_h_black); grandparent->SetColor(_tree_h_red); // Move up the tree tree = grandparent; } else // Uncle is a black node { if (tree == parent->GetLeft()) { // Case 2 - Move up and rotate tree = parent; RotateRight(tree); } // Case 3 - Make no changes to _root tree // Change colors for Case 2 / Case 3 parent->SetColor(_tree_h_black); grandparent->SetColor(_tree_h_red); RotateLeft(grandparent); } } // Have to adjust parent for new tree node parent = tree->GetParent(); } // Mongoose 2002.02.17, Color root black ( heh ) _root->SetColor(_tree_h_black); } bool _error; /* Error reporting for operator use */ unsigned int _num_elements; /* Number of nodes in this tree */ TreeNode *_root; /* Root node */ }; #endif