Files
core/Common/cfcpp/RBTree/rbtree.cpp
2022-09-02 14:53:37 +03:00

435 lines
9.4 KiB
C++

#include "rbtree.h"
#include "rbtreeexception.h"
using namespace RedBlackTree;
RBTree::RBTree(PIRBNode root) : root(root)
{}
const PIRBNode RBTree::getRoot() const
{
return root;
}
void RBTree::setRoot(const PIRBNode &newRoot)
{
root = newRoot;
}
bool RBTree::TryLookup(PIRBNode templ, PIRBNode &val)
{
PIRBNode n = LookupNode(templ);
if (n == nullptr)
{
val.reset();
return false;
}
else
{
val = n;
return true;
}
}
void RBTree::Insert(PIRBNode newNode)
{
newNode->setColor(Color::RED);
PIRBNode insertedNode = newNode;
if (getRoot() == nullptr)
{
setRoot(insertedNode);
}
else
{
PIRBNode n = getRoot();
while (true)
{
int compResult = newNode->CompareTo(n);
if (compResult == 0)
{
throw RBTreeDuplicatedItemException(L"RBNode " + newNode->ToString() + L" already present in tree");
//n->Value = value;
//return;
}
else if (compResult < 0)
{
if (n->getLeft() == nullptr)
{
n->setLeft(insertedNode);
break;
}
else
{
n = n->getLeft();
}
}
else
{
//assert compResult > 0;
if (n->getRight() == nullptr)
{
n->setRight(insertedNode);
break;
}
else
{
n = n->getRight();
}
}
}
insertedNode->setParent(n);
}
InsertCase1(insertedNode);
// if (NodeInserted != nullptr)
// {
// NodeInserted(insertedNode);
// }
//Trace.WriteLine(" ");
//Print();
}
void RBTree::Delete(PIRBNode templ, PIRBNode &deletedAlt)
{
deletedAlt.reset();
PIRBNode n = LookupNode(templ);
templ = n;
if (n == nullptr)
return; // Key not found, do nothing
if (n->getLeft() != nullptr && n->getRight() != nullptr)
{
// Copy key/value from predecessor and then delete it instead
PIRBNode pred = MaximumNode(n->getLeft());
pred->AssignValueTo(n);
n = pred;
deletedAlt = pred;
}
//assert n->left == null || n->right == null;
PIRBNode child = (n->getRight() == nullptr) ? n->getLeft() : n->getRight();
if (NodeColor(n) == Color::BLACK)
{
n->setColor(NodeColor(child));
DeleteCase1(n);
}
ReplaceNode(n, child);
if (NodeColor(getRoot()) == Color::RED)
{
getRoot()->setColor(Color::BLACK);
}
return;
}
void RBTree::VisitTree(Action<PIRBNode> action)
{
PIRBNode walker = getRoot();
if (walker != nullptr)
DoVisitTree(action, walker);
}
Color RBTree::NodeColor(PIRBNode n)
{
return n == nullptr ? Color::BLACK : n->getColor();
}
PIRBNode RBTree::MaximumNode(PIRBNode n)
{
while (n->getRight() != nullptr)
{
n = n->getRight();
}
return n;
}
PIRBNode RBTree::LookupNode(PIRBNode templ)
{
PIRBNode n = getRoot();
while (n != nullptr)
{
int compResult = templ->CompareTo(n);
if (compResult == 0)
{
return n;
}
else if (compResult < 0)
{
n = n->getLeft();
}
else
{
//assert compResult > 0;
n = n->getRight();
}
}
return n;
}
void RBTree::ReplaceNode(PIRBNode oldn, PIRBNode newn)
{
if (oldn->getParent() == nullptr)
{
setRoot(newn);
}
else
{
if (oldn == oldn->getParent()->getLeft())
oldn->getParent()->setLeft(newn);
else
oldn->getParent()->setRight(newn);
}
if (newn != nullptr)
{
newn->setParent(oldn->getParent());
}
}
void RBTree::RotateLeft(PIRBNode n)
{
PIRBNode r = n->getRight();
ReplaceNode(n, r);
n->setRight(r->getLeft());
if (r->getLeft() != nullptr)
{
r->getLeft()->setParent(n);
}
r->setLeft(n);
n->setParent(r);
}
void RBTree::RotateRight(PIRBNode n)
{
PIRBNode l = n->getLeft();
ReplaceNode(n, l);
n->setLeft(l->getRight());
if (l->getRight() != nullptr)
{
l->getRight()->setParent(n);
}
l->setRight(n);
n->setParent(l);
}
void RBTree::InsertCase1(PIRBNode n)
{
if (n->getParent() == nullptr)
n->setColor(Color::BLACK);
else
InsertCase2(n);
}
void RBTree::InsertCase2(PIRBNode n)
{
if (NodeColor(n->getParent()) == Color::BLACK)
return; // Tree is still valid
else
InsertCase3(n);
}
void RBTree::InsertCase3(PIRBNode n)
{
if (NodeColor(n->Uncle()) == Color::RED)
{
n->getParent()->setColor(Color::BLACK);
n->Uncle()->setColor(Color::BLACK);
n->Grandparent()->setColor(Color::RED);
InsertCase1(n->Grandparent());
}
else
{
InsertCase4(n);
}
}
void RBTree::InsertCase4(PIRBNode n)
{
if (n == n->getParent()->getRight() && n->getParent() == n->Grandparent()->getLeft())
{
RotateLeft(n->getParent());
n = n->getLeft();
}
else if (n == n->getParent()->getLeft() && n->getParent() == n->Grandparent()->getRight())
{
RotateRight(n->getParent());
n = n->getRight();
}
InsertCase5(n);
}
void RBTree::InsertCase5(PIRBNode n)
{
n->getParent()->setColor(Color::BLACK);
n->Grandparent()->setColor(Color::RED);
if (n == n->getParent()->getLeft() && n->getParent() == n->Grandparent()->getLeft())
{
RotateRight(n->Grandparent());
}
else
{
//assert n == n->getParent().right && n->getParent() == n->grandparent().right;
RotateLeft(n->Grandparent());
}
}
void RBTree::DeleteCase1(PIRBNode n)
{
if (n->getParent() == nullptr)
return;
else
DeleteCase2(n);
}
void RBTree::DeleteCase2(PIRBNode n)
{
if (NodeColor(n->Sibling()) == Color::RED)
{
n->getParent()->setColor(Color::RED);
n->Sibling()->setColor(Color::BLACK);
if (n == n->getParent()->getLeft())
RotateLeft(n->getParent());
else
RotateRight(n->getParent());
}
DeleteCase3(n);
}
void RBTree::DeleteCase3(PIRBNode n)
{
if (NodeColor(n->getParent()) == Color::BLACK &&
NodeColor(n->Sibling()) == Color::BLACK &&
NodeColor(n->Sibling()->getLeft()) == Color::BLACK &&
NodeColor(n->Sibling()->getRight()) == Color::BLACK)
{
n->Sibling()->setColor(Color::RED);
DeleteCase1(n->getParent());
}
else
DeleteCase4(n);
}
void RBTree::DeleteCase4(PIRBNode n)
{
if (NodeColor(n->getParent()) == Color::RED &&
NodeColor(n->Sibling()) == Color::BLACK &&
NodeColor(n->Sibling()->getLeft()) == Color::BLACK &&
NodeColor(n->Sibling()->getRight()) == Color::BLACK)
{
n->Sibling()->setColor(Color::RED);
n->getParent()->setColor(Color::BLACK);
}
else
DeleteCase5(n);
}
void RBTree::DeleteCase5(PIRBNode n)
{
if (n == n->getParent()->getLeft() &&
NodeColor(n->Sibling()) == Color::BLACK &&
NodeColor(n->Sibling()->getLeft()) == Color::RED &&
NodeColor(n->Sibling()->getRight()) == Color::BLACK)
{
n->Sibling()->setColor(Color::RED);
n->Sibling()->getLeft()->setColor(Color::BLACK);
RotateRight(n->Sibling());
}
else if (n == n->getParent()->getRight() &&
NodeColor(n->Sibling()) == Color::BLACK &&
NodeColor(n->Sibling()->getRight()) == Color::RED &&
NodeColor(n->Sibling()->getLeft()) == Color::BLACK)
{
n->Sibling()->setColor(Color::RED);
n->Sibling()->getRight()->setColor(Color::BLACK);
RotateLeft(n->Sibling());
}
DeleteCase6(n);
}
void RBTree::DeleteCase6(PIRBNode n)
{
n->Sibling()->setColor(NodeColor(n->getParent()));
n->getParent()->setColor(Color::BLACK);
if (n == n->getParent()->getLeft())
{
//assert nodeColor(n->sibling().right) == Color::RED;
n->Sibling()->getRight()->setColor(Color::BLACK);
RotateLeft(n->getParent());
}
else
{
//assert nodeColor(n->sibling().left) == Color::RED;
n->Sibling()->getLeft()->setColor(Color::BLACK);
RotateRight(n->getParent());
}
}
void RBTree::DoVisitTree(Action<PIRBNode> action, PIRBNode walker)
{
if (walker->getLeft() != nullptr)
{
DoVisitTree(action, walker->getLeft());
}
if (action != nullptr)
action(walker);
if (walker->getRight() != nullptr)
{
DoVisitTree(action, walker->getRight());
}
}
void RBTree::VisitTreeNodes(Action<PIRBNode> action)
{
//IN Order visit
PIRBNode walker = getRoot();
if (walker != nullptr)
DoVisitTreeNodes(action, walker);
}
void RBTree::DoVisitTreeNodes(Action<PIRBNode> action, PIRBNode walker)
{
if (walker->getLeft() != nullptr)
{
DoVisitTreeNodes(action, walker->getLeft());
}
if (action != nullptr)
action(walker);
if (walker->getRight() != nullptr)
{
DoVisitTreeNodes(action, walker->getRight());
}
}
RBTree::iterator::iterator(RBTree &tree, bool end)
{
Action<PIRBNode> inserter = [&] (PIRBNode pNode)
{
heap.push_back(pNode);
};
tree.VisitTreeNodes(inserter);
current = end ? heap.end() : heap.begin();
}