/* Copyright (c) <2003-2019> * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely */ #ifndef __D_MAP__ #define __D_MAP__ template class dMap { public: class dTreeNode { enum REDBLACK_COLOR { RED = true, BLACK = false }; dTreeNode (const KEY &key, dTreeNode* parentNode) :m_info() ,m_key(key) ,m_left(nullptr) ,m_right(nullptr) ,m_parent(parentNode) ,m_color(false) ,m_inTree(false) { SetColor(RED); SetInTreeFlag(true); } dTreeNode (const OBJECT &info, const KEY &key, dTreeNode* parentNode) :m_info(info) ,m_key(key) ,m_left(nullptr) ,m_right(nullptr) ,m_parent(parentNode) ,m_color(false) ,m_inTree(false) { SetColor(RED); SetInTreeFlag(true); } virtual ~dTreeNode () { } void SetInTreeFlag(bool flag) { m_inTree = flag; } bool GetColor() const { return m_color; } void SetColor(bool color) { m_color = color; } dTreeNode& operator= (dTreeNode& src) { dAssert (0); return* this; } dTreeNode* GetLeft () const { return m_left; } dTreeNode* GetRight () const { return m_right; } dTreeNode* GetParent () { return m_parent; } void SetLeft (dTreeNode* const node) { m_left = node; } void SetRight (dTreeNode* const node) { m_right = node; } void SetParent (dTreeNode* const node) { m_parent = node; } public: const KEY& GetKey() const { return m_key; } OBJECT& GetInfo() { return m_info; } dTreeNode* Minimum() const { dTreeNode* ptr = (dTreeNode*)this; for (; ptr->m_left; ptr = ptr->m_left); return ptr; } dTreeNode* Next() const { if (m_right) { return m_right->Minimum(); } dTreeNode* node = (dTreeNode*)this; dTreeNode* ptr = m_parent; for (; ptr && node == ptr->m_right; ptr = ptr->m_parent) { node = ptr; } return ptr; } void Unlink(dTreeNode** const head) { dTreeNode* const node = this; node->SetInTreeFlag(false); if (!node->m_left || !node->m_right) { // y has a nullptr node as a child dTreeNode* const endNode = node; // x is y's only child dTreeNode* child = endNode->m_right; if (endNode->m_left) { child = endNode->m_left; } // remove y from the parent chain if (child) { child->m_parent = endNode->m_parent; } if (endNode->m_parent) { if (endNode == endNode->m_parent->m_left) { endNode->m_parent->m_left = child; } else { endNode->m_parent->m_right = child; } } else { *head = child; } if (endNode->GetColor() == BLACK) { endNode->m_parent->RemoveFixup(child, head); } } else { // find tree successor with a nullptr node as a child dTreeNode* endNode = node->m_right; while (endNode->m_left != nullptr) { endNode = endNode->m_left; } // x is y's only child dTreeNode* const child = endNode->m_right; endNode->m_left = node->m_left; node->m_left->m_parent = endNode; dTreeNode* endNodeParent = endNode; if (endNode != node->m_right) { if (child) { child->m_parent = endNode->m_parent; } endNode->m_parent->m_left = child; endNode->m_right = node->m_right; node->m_right->m_parent = endNode; endNodeParent = endNode->m_parent; } if (node == *head) { *head = endNode; } else if (node == node->m_parent->m_left) { node->m_parent->m_left = endNode; } else { node->m_parent->m_right = endNode; } endNode->m_parent = node->m_parent; bool oldColor = endNode->GetColor(); endNode->SetColor(node->GetColor()); node->SetColor(oldColor); if (oldColor == BLACK) { endNodeParent->RemoveFixup(child, head); } } } void RotateLeft(dTreeNode** const head) { dTreeNode* const me = this; dTreeNode* const child = me->m_right; //dAssert(child); me->m_right = child->m_left; if (child->m_left != nullptr) { child->m_left->m_parent = me; } if (child != nullptr) { child->m_parent = me->m_parent; } if (me->m_parent) { if (me == me->m_parent->m_left) { me->m_parent->m_left = child; } else { me->m_parent->m_right = child; } } else { *head = child; } // link child and me child->m_left = me; if (me != nullptr) { me->m_parent = child; } } // rotate node me to right * void RotateRight(dTreeNode** const head) { dTreeNode* const me = this; dTreeNode* const child = me->m_left; //dAssert(child); me->m_left = child->m_right; if (child->m_right != nullptr) { child->m_right->m_parent = me; } // establish child->m_parent link if (child != nullptr) { child->m_parent = me->m_parent; } if (me->m_parent) { if (me == me->m_parent->m_right) { me->m_parent->m_right = child; } else { me->m_parent->m_left = child; } } else { *head = child; } // link me and child child->m_right = me; if (me != nullptr) { me->m_parent = child; } } void RemoveFixup(dTreeNode* const me, dTreeNode** const head) { dTreeNode* ptr = this; dTreeNode* node = me; while ((node != *head) && (!node || node->GetColor() == BLACK)) { if (node == ptr->m_left) { if (!ptr) { return; } dTreeNode* tmp = ptr->m_right; if (!tmp) { return; } if (tmp->GetColor() == RED) { tmp->SetColor(BLACK); ptr->SetColor(RED); ptr->RotateLeft(head); tmp = ptr->m_right; if (!tmp) { return; } } if ((!tmp->m_left || (tmp->m_left->GetColor() == BLACK)) && (!tmp->m_right || (tmp->m_right->GetColor() == BLACK))) { tmp->SetColor(RED); node = ptr; ptr = ptr->m_parent; continue; } else if (!tmp->m_right || (tmp->m_right->GetColor() == BLACK)) { tmp->m_left->SetColor(BLACK); tmp->SetColor(RED); tmp->RotateRight(head); tmp = ptr->m_right; //if (!ptr || !tmp) { if (!tmp) { return; } } tmp->SetColor(ptr->GetColor()); if (tmp->m_right) { tmp->m_right->SetColor(BLACK); } if (ptr) { ptr->SetColor(BLACK); ptr->RotateLeft(head); } node = *head; } else { if (!ptr) { return; } dTreeNode* tmp = ptr->m_left; if (!tmp) { return; } if (tmp->GetColor() == RED) { tmp->SetColor(BLACK); ptr->SetColor(RED); ptr->RotateRight(head); tmp = ptr->m_left; if (!tmp) { return; } } if ((!tmp->m_right || (tmp->m_right->GetColor() == BLACK)) && (!tmp->m_left || (tmp->m_left->GetColor() == BLACK))) { tmp->SetColor(RED); node = ptr; ptr = ptr->m_parent; continue; } else if (!tmp->m_left || (tmp->m_left->GetColor() == BLACK)) { tmp->m_right->SetColor(BLACK); tmp->SetColor(RED); tmp->RotateLeft(head); tmp = ptr->m_left; //if (!ptr || !tmp) { if (!tmp) { return; } } tmp->SetColor(ptr->GetColor()); if (tmp->m_left) { tmp->m_left->SetColor(BLACK); } if (ptr) { ptr->SetColor(BLACK); ptr->RotateRight(head); } node = *head; } } if (node) { node->SetColor(BLACK); } } void InsertFixup(dTreeNode** const head) { dTreeNode* ptr = this; // check Red-Black properties //dAssert((ptr == *head) || ptr->m_parent); while ((ptr != *head) && (ptr->m_parent->GetColor() == RED)) { // we have a violation //dAssert(ptr->m_parent); //dAssert(ptr->m_parent->m_parent); if (ptr->m_parent == ptr->m_parent->m_parent->m_left) { dTreeNode* const tmp = ptr->m_parent->m_parent->m_right; if (tmp && (tmp->GetColor() == RED)) { // uncle is RED ptr->m_parent->SetColor(BLACK); tmp->SetColor(BLACK); ptr->m_parent->m_parent->SetColor(RED); ptr = ptr->m_parent->m_parent; } else { // uncle is BLACK if (ptr == ptr->m_parent->m_right) { // make ptr a left child ptr = ptr->m_parent; ptr->RotateLeft(head); } ptr->m_parent->SetColor(BLACK); if (ptr->m_parent->m_parent) { ptr->m_parent->m_parent->SetColor(RED); ptr->m_parent->m_parent->RotateRight(head); } } } else { //dAssert (ptr->m_parent == ptr->m_parent->m_parent->m_right); // mirror image of above code dTreeNode* const tmp = ptr->m_parent->m_parent->m_left; if (tmp && (tmp->GetColor() == RED)) { //uncle is RED ptr->m_parent->SetColor(BLACK); tmp->SetColor(BLACK); ptr->m_parent->m_parent->SetColor(RED); ptr = ptr->m_parent->m_parent; } else { // uncle is BLACK if (ptr == ptr->m_parent->m_left) { ptr = ptr->m_parent; ptr->RotateRight(head); } ptr->m_parent->SetColor(BLACK); if (ptr->m_parent->m_parent->GetColor() == BLACK) { ptr->m_parent->m_parent->SetColor(RED); ptr->m_parent->m_parent->RotateLeft(head); } } } } (*head)->SetColor(BLACK); } private: OBJECT m_info; KEY m_key; dTreeNode* m_left; dTreeNode* m_right; dTreeNode* m_parent; bool m_color; bool m_inTree; friend class dMap; }; class Iterator { public: Iterator(const dMap &me) { m_ptr = nullptr; m_tree = &me; } ~Iterator() { } void Begin() { m_ptr = m_tree->Minimum(); } void End() { m_ptr = m_tree->Maximum(); } void Set (dTreeNode* const node) { m_ptr = node; } operator int() const { return m_ptr != nullptr; } void operator++ () { //dAssert (m_ptr); m_ptr = m_ptr->Next(); } void operator++ (int) { //dAssert (m_ptr); m_ptr = m_ptr->Next(); } void operator-- () { //dAssert (m_ptr); m_ptr = m_ptr->Prev(); } void operator-- (int) { //dAssert (m_ptr); m_ptr = m_ptr->Prev(); } OBJECT &operator* () const { return ((dTreeNode*)m_ptr)->GetInfo(); } dTreeNode* GetNode() const { return (dTreeNode*)m_ptr; } KEY GetKey () const { dTreeNode* const tmp = (dTreeNode*)m_ptr; return tmp ? tmp->GetKey() : KEY(0); } private: dTreeNode* m_ptr; const dMap* m_tree; }; // *********************************************************** // member functions // *********************************************************** public: dMap (); virtual ~dMap (); operator int() const; int GetCount() const; dTreeNode* GetRoot () const; dTreeNode* Minimum () const; dTreeNode* Maximum () const; dTreeNode* Find (KEY key) const; dTreeNode* FindGreater (KEY key) const; dTreeNode* FindGreaterEqual (KEY key) const; dTreeNode* FindLessEqual (KEY key) const; dTreeNode* GetNodeFromInfo (OBJECT &info) const; dTreeNode* Insert (KEY key); dTreeNode* Insert (const OBJECT &element, KEY key); dTreeNode* Insert (const OBJECT &element, KEY key, bool& elementWasInTree); dTreeNode* Insert (dTreeNode* const node, KEY key); dTreeNode* Replace (OBJECT &element, KEY key); dTreeNode* ReplaceKey (KEY oldKey, KEY newKey); dTreeNode* ReplaceKey (dTreeNode* const node, KEY key); void Unlink (dTreeNode* const node); void Remove (KEY key); void Remove (dTreeNode* const node); void RemoveAll (); bool SanityCheck () const; // *********************************************************** // member variables // *********************************************************** private: void RemoveAllLow (dTreeNode* const root); int CompareKeys (const KEY &key0, const KEY &key1) const; bool SanityCheck (dTreeNode* const ptr, int height) const; int m_count; dTreeNode* m_head; friend class dTreeNode; }; template dMap::dMap () { m_count = 0; m_head = nullptr; } template dMap::~dMap () { RemoveAll(); } template dMap::operator int() const { return m_head != nullptr; } template int dMap::GetCount() const { return m_count; } template typename dMap::dTreeNode* dMap::Minimum () const { return m_head ? (dTreeNode*) m_head->Minimum() : nullptr; } template typename dMap::dTreeNode* dMap::Maximum () const { return m_head ? (dTreeNode*) m_head->Maximum() : nullptr; } template typename dMap::dTreeNode* dMap::GetRoot () const { return m_head; } template typename dMap::dTreeNode* dMap::Find (KEY key) const { if (m_head == nullptr) { return nullptr; } dTreeNode* ptr = m_head; while (ptr != nullptr) { int val = CompareKeys (ptr->m_key, key); if (!val) { break; } if (val < 0) { ptr = ptr->GetLeft(); } else { ptr = ptr->GetRight(); } } return ptr; } template typename dMap::dTreeNode* dMap::GetNodeFromInfo (OBJECT &info) const { dTreeNode* node = (dTreeNode*) &info; int offset = ((char*) &node->m_info) - ((char *) node); node = (dTreeNode*) (((char *) node) - offset); // dAssert (node->IsInTree ()); dAssert (&node->GetInfo () == &info); return (node->IsInTree ()) ? node : nullptr; } template typename dMap::dTreeNode* dMap::FindGreater (KEY key) const { if (m_head == nullptr) { return nullptr; } dTreeNode* prev = nullptr; dTreeNode* ptr = m_head; int val = 0; while (ptr != nullptr) { val = CompareKeys (ptr->m_key, key); if (!val) { return (dTreeNode*) ptr->Next(); } prev = ptr; if (val < 0) { ptr = ptr->GetLeft(); } else { ptr = ptr->GetRight(); } } if (val > 0) { while (prev->m_parent && (prev->m_parent->m_right == prev)) { prev = prev->GetParent(); } prev = prev->GetParent(); } return (dTreeNode*) prev; } template typename dMap::dTreeNode* dMap::FindGreaterEqual (KEY key) const { if (m_head == nullptr) { return nullptr; } dTreeNode* prev = nullptr; dTreeNode* ptr = m_head; int val = 0; while (ptr != nullptr) { val = CompareKeys (ptr->m_key, key); if (!val) { return ptr; } prev = ptr; if (val < 0) { ptr = ptr->GetLeft(); } else { ptr = ptr->GetRight(); } } if (val > 0) { while (prev->m_parent && (prev->m_parent->m_right == prev)) { prev = prev->GetParent(); } prev = prev->GetParent(); } return (dTreeNode*) prev; } template typename dMap::dTreeNode* dMap::FindLessEqual (KEY key) const { if (m_head == nullptr) { return nullptr; } dTreeNode* prev = nullptr; dTreeNode* ptr = m_head; int val = 0; while (ptr != nullptr) { val = CompareKeys (ptr->m_key, key); if (!val) { return ptr; } prev = ptr; if (val < 0) { ptr = ptr->GetLeft(); } else { ptr = ptr->GetRight(); } } if (val < 0) { while (prev->m_parent && (prev->m_parent->m_left == prev)) { prev = prev->GetParent(); } prev = prev->GetParent(); } return (dTreeNode*) prev; } template typename dMap::dTreeNode* dMap::Insert (KEY key) { dTreeNode* parent = nullptr; dTreeNode* ptr = m_head; int val = 0; while (ptr != nullptr) { parent = ptr; val = CompareKeys (ptr->m_key, key); if (val < 0) { ptr = ptr->GetLeft(); } else if (val > 0) { ptr = ptr->GetRight(); } else { return ptr; } } m_count ++; ptr = new dTreeNode (key, parent); if (!parent) { m_head = ptr; } else { if (val < 0) { parent->m_left = ptr; } else { parent->m_right = ptr; } } ptr->InsertFixup ((dTreeNode**)&m_head); return ptr; } template typename dMap::dTreeNode* dMap::Insert (const OBJECT &element, KEY key, bool& elementWasInTree) { dTreeNode* parent = nullptr; dTreeNode* ptr = m_head; int val = 0; elementWasInTree = false; while (ptr != nullptr) { parent = ptr; val = CompareKeys (ptr->m_key, key); if (val < 0) { ptr = ptr->GetLeft(); } else if (val > 0) { ptr = ptr->GetRight(); } else { elementWasInTree = true; return ptr; } } m_count ++; ptr = new dTreeNode (element, key, parent); if (!parent) { m_head = ptr; } else { if (val < 0) { parent->m_left = ptr; } else { parent->m_right = ptr; } } ptr->InsertFixup ((dTreeNode**)&m_head); return ptr; } template typename dMap::dTreeNode* dMap::Insert (const OBJECT &element, KEY key) { bool foundState; dTreeNode* node = Insert (element, key, foundState); if (foundState) { node = nullptr; } return node; } template typename dMap::dTreeNode* dMap::Insert (typename dMap::dTreeNode* const node, KEY key) { int val = 0; dTreeNode* ptr = m_head; dTreeNode* parent = nullptr; while (ptr != nullptr) { parent = ptr; val = CompareKeys (ptr->m_key, key); if (val < 0) { ptr = ptr->GetLeft(); } else if (val > 0) { ptr = ptr->GetRight(); } else { return nullptr; } } m_count ++; ptr = node; ptr->m_key = key; ptr->Initdata (parent); if (!parent) { m_head = ptr; } else { if (val < 0) { parent->m_left = ptr; } else { parent->m_right = ptr; } } ptr->InsertFixup ((dTreeNode**)&m_head); return ptr; } template typename dMap::dTreeNode* dMap::Replace (OBJECT &element, KEY key) { dTreeNode* parent = nullptr; dTreeNode* ptr = m_head; int val = 0; while (ptr != nullptr) { parent = ptr; val = CompareKeys (ptr->m_key, key); if (val == 0) { ptr->m_info = element; return ptr; } if (val < 0) { ptr = ptr->GetLeft(); } else { ptr = ptr->GetRight(); } } ptr = new dTreeNode (element, key, parent); if (!parent) { m_head = ptr; } else { if (val < 0) { parent->m_left = ptr; } else { parent->m_right = ptr; } } ptr->InsertFixup ((dTreeNode**)&m_head); return ptr; } template typename dMap::dTreeNode* dMap::ReplaceKey (typename dMap::dTreeNode* node, KEY key) { Unlink(node); dTreeNode* const ptr = Insert (node, key); dAssert (ptr); return ptr; } template typename dMap::dTreeNode* dMap::ReplaceKey (KEY oldKey, KEY newKey) { dTreeNode* const node = Find (oldKey); return node ? ReplaceKey (node, newKey) : nullptr; } template void dMap::Unlink (typename dMap::dTreeNode* const node) { m_count --; node->Unlink((dTreeNode** )&m_head); } template void dMap::Remove (typename dMap::dTreeNode* const node) { m_count --; node->Unlink ((dTreeNode** )&m_head); delete node; } template void dMap::Remove (KEY key) { // find node in tree dTreeNode* const node = Find (key); if (node) { Remove (node); } } template void dMap::RemoveAllLow (dTreeNode* const root) { if (root->m_left) { RemoveAllLow((dTreeNode*)root->m_left); } if (root->m_right) { RemoveAllLow ((dTreeNode*)root->m_right); } root->SetInTreeFlag(false); delete root; } template void dMap::RemoveAll () { if (m_head) { m_count = 0; dTreeNode* root; for (root = m_head; root->m_parent; root = (dTreeNode*)root->m_parent); RemoveAllLow(root); m_head = nullptr; } } template bool dMap::SanityCheck () const { return SanityCheck (m_head, 0); } template bool dMap::SanityCheck (typename dMap::dTreeNode* ptr, int height) const { if (!ptr) { return true; } if (ptr->m_left) { if (CompareKeys (ptr->m_key, ptr->GetLeft()->m_key) > 0) { return false; } } if (ptr->m_right) { if (CompareKeys (ptr->m_key, ptr->GetRight()->m_key) < 0) { return false; } } if (ptr->GetColor() == dTreeNode::BLACK) { height ++; } else if (!((!ptr->m_left || (ptr->m_left->GetColor() == dTreeNode::BLACK)) && (!ptr->m_right || (ptr->m_right->GetColor() == dTreeNode::BLACK)))) { return false; } if (!ptr->m_left && !ptr->m_right) { int bh = 0; for (dTreeNode* x = ptr; x; x = x->GetParent()) { if (x->GetColor() == dTreeNode::BLACK) { bh ++; } } if (bh != height) { return false; } } if (ptr->m_left && !SanityCheck (ptr->GetLeft(), height)) { return false; } if (ptr->m_right && !SanityCheck (ptr->GetRight(), height)) { return false; } return true; } template int dMap::CompareKeys (const KEY &key0, const KEY &key1) const { if (key1 < key0) { return - 1; } if (key1 > key0) { return 1; } return 0; } #endif