RBTree implementation with const null_node
This commit is contained in:
parent
2050eb4d46
commit
da1dfd4c13
@ -2,10 +2,14 @@
|
||||
|
||||
namespace GraphC::GraphModel {
|
||||
|
||||
|
||||
Attribute::Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title)
|
||||
: type(_type), id(_id), parent_node(_parent_node), title(_title)
|
||||
{}
|
||||
|
||||
Attribute::Attribute() : Attribute(id_t_invalid, nullptr, Attribute::Type::Static, "NULL_ATTR")
|
||||
{}
|
||||
|
||||
const RBTree<id_t, Edge*>& Attribute::getIncomingEdges() const {
|
||||
return incoming_edges;
|
||||
}
|
||||
|
||||
@ -6,4 +6,7 @@ Edge::Edge(id_t _id, id_t _from_attr_id, id_t _to_attr_id)
|
||||
: id(_id), to_attr_id(_to_attr_id), from_attr_id(_from_attr_id)
|
||||
{}
|
||||
|
||||
Edge::Edge() : Edge(id_t_invalid, id_t_invalid, id_t_invalid)
|
||||
{}
|
||||
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ bool Graph::tryGetNode(id_t node_id, Node** result) const {
|
||||
|
||||
void Graph::deleteNode(Node& n){
|
||||
for(const auto& attr_p : n.attributes)
|
||||
deleteAttribute(*attr_p.second);
|
||||
deleteAttribute(*attr_p.value);
|
||||
useful_assert(nodes.tryDelete(n.id),
|
||||
format("can't delete node with id %i", n.id));
|
||||
}
|
||||
@ -141,12 +141,12 @@ Attribute* Graph::createAttribute(Attribute&& a){
|
||||
|
||||
void Graph::deleteAttribute(Attribute& a){
|
||||
for(const auto& edge_p : a.incoming_edges){
|
||||
useful_assert(edges.tryDelete(edge_p.second->id),
|
||||
format("can't find edge with id %i", edge_p.second->id));
|
||||
useful_assert(edges.tryDelete(edge_p.value->id),
|
||||
format("can't find edge with id %i", edge_p.value->id));
|
||||
}
|
||||
for(const auto& edge_p : a.outgoing_edges){
|
||||
useful_assert(edges.tryDelete(edge_p.second->id),
|
||||
format("can't find edge with id %i", edge_p.second->id));
|
||||
useful_assert(edges.tryDelete(edge_p.value->id),
|
||||
format("can't find edge with id %i", edge_p.value->id));
|
||||
}
|
||||
useful_assert(attributes.tryDelete(a.id),
|
||||
format("can't delete attribute with id %i", a.id));
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
namespace GraphC::GraphModel {
|
||||
|
||||
typedef i32 id_t;
|
||||
#define id_t_invalid ((id_t)-1)
|
||||
|
||||
class IdGenerator {
|
||||
id_t next_id=1;
|
||||
@ -39,6 +40,8 @@ public:
|
||||
Node *const parent_node;
|
||||
std::string title;
|
||||
|
||||
///@warning empty constructor for RBTree null-value node, do not use it
|
||||
Attribute();
|
||||
Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title);
|
||||
|
||||
const RBTree<id_t, Edge*>& getIncomingEdges() const;
|
||||
@ -54,6 +57,8 @@ public:
|
||||
const id_t id;
|
||||
std::string title;
|
||||
|
||||
///@warning empty constructor for RBTree null-value node, do not use it
|
||||
Node();
|
||||
Node(id_t _id, std::string _title);
|
||||
|
||||
const RBTree<id_t, Attribute*>& getAttributes() const;
|
||||
@ -64,6 +69,8 @@ struct Edge {
|
||||
const id_t to_attr_id;
|
||||
const id_t from_attr_id;
|
||||
|
||||
///@warning empty constructor for RBTree null-value node, do not use it
|
||||
Edge();
|
||||
Edge(id_t _id, id_t _from_attr_id, id_t _to_attr_id);
|
||||
};
|
||||
|
||||
|
||||
@ -6,6 +6,9 @@ Node::Node(id_t _id, std::string _title)
|
||||
: id(_id), title(_title)
|
||||
{}
|
||||
|
||||
Node::Node() : Node(id_t_invalid, "NULL_NODE")
|
||||
{}
|
||||
|
||||
const RBTree<id_t, Attribute*>& Node::getAttributes() const {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
405
src/RBTree.hpp
405
src/RBTree.hpp
@ -1,80 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../dependencies/kerep/src/base/base.h"
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include "UsefulException.hpp"
|
||||
|
||||
// typedef char* TKey;
|
||||
// typedef char* TVal;
|
||||
template<typename TKey, typename TVal>
|
||||
class RBTree {
|
||||
enum class Color {
|
||||
Red, Black
|
||||
};
|
||||
|
||||
struct Node {
|
||||
TKey key;
|
||||
// public version of struct Node
|
||||
// TreeIterator returns a reference to KVPair to hide all other stuff from users
|
||||
public:
|
||||
struct KVPair {
|
||||
// members are in reverse order to minimize padding and make struct Node smaller
|
||||
|
||||
TVal value;
|
||||
TKey key;
|
||||
|
||||
KVPair(TKey& k, TVal& v) : value(v), key(k)
|
||||
{}
|
||||
|
||||
protected:
|
||||
// special constructor for tree leafs (null nodes)
|
||||
// leaves key and value uninitialized
|
||||
KVPair()
|
||||
{}
|
||||
};
|
||||
|
||||
private:
|
||||
struct Node : public KVPair {
|
||||
// stacks with KVPair::key if it is 32-bit or smaller
|
||||
Color color;
|
||||
Node* parent;
|
||||
Node* left = nullptr;
|
||||
Node* right = nullptr;
|
||||
Node* left;
|
||||
Node* right;
|
||||
|
||||
Node(TKey _key, TVal _val, Color _color, Node* _parent)
|
||||
: key(_key), value(_val), color(_color), parent(_parent)
|
||||
{
|
||||
Node(TKey& _key, TVal& _val, Color _color, Node* _parent, Node* _left, Node* _right)
|
||||
: KVPair(_key, _val), color(_color), parent(_parent), left(_left), right(_right)
|
||||
{}
|
||||
|
||||
Node() : color(Color::Black), parent(this), left(this), right(this)
|
||||
{}
|
||||
|
||||
bool isLeaf() const {
|
||||
return parent == this;
|
||||
}
|
||||
|
||||
~Node(){
|
||||
if(!left->isLeaf())
|
||||
delete left;
|
||||
if(!right->isLeaf())
|
||||
delete right;
|
||||
}
|
||||
|
||||
inline Node* getSibling(){
|
||||
if(parent == nullptr)
|
||||
return nullptr;
|
||||
else if(parent->left == this)
|
||||
return parent->right;
|
||||
else return parent->left;
|
||||
}
|
||||
|
||||
inline Node* getGrandparent(){
|
||||
if(parent == nullptr)
|
||||
return nullptr;
|
||||
else return parent->parent;
|
||||
}
|
||||
|
||||
inline Node* getUncle(){
|
||||
if(parent == nullptr)
|
||||
return nullptr;
|
||||
return parent->getSibling();
|
||||
}
|
||||
|
||||
// n should be not null
|
||||
Node* getMinChild(){
|
||||
/// if is leaf returns itself
|
||||
Node* getMinChild() {
|
||||
Node* n = this;
|
||||
while(n->left != nullptr)
|
||||
while(!n->left->isLeaf())
|
||||
n = n->left;
|
||||
return n;
|
||||
}
|
||||
|
||||
// n should be not null
|
||||
Node* getMaxChild(){
|
||||
/// if is leaf returns itself
|
||||
Node* getMaxChild() {
|
||||
Node* n = this;
|
||||
while(n->right != nullptr)
|
||||
while(!n->right->isLeaf())
|
||||
n = n->right;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Node* root = nullptr;
|
||||
static Node null_node;
|
||||
static Node* null_node_ptr;
|
||||
Node* root = &null_node;
|
||||
|
||||
|
||||
///@returns null if root is null
|
||||
Node* findParentForKey(TKey key) const {
|
||||
Node* n = root;
|
||||
Node* parent = nullptr;
|
||||
while(n != nullptr){
|
||||
Node* parent = null_node_ptr;
|
||||
while(n != null_node_ptr){
|
||||
parent = n;
|
||||
if(key < n->key)
|
||||
n = n->left;
|
||||
@ -90,7 +97,7 @@ class RBTree {
|
||||
Node* y = x->right;
|
||||
// 2. move y to the position of x
|
||||
y->parent = x->parent;
|
||||
if (x->parent != nullptr){ // x != root
|
||||
if(x->parent != null_node_ptr){ // x != root
|
||||
if(x == x->parent->left)
|
||||
x->parent->left = y;
|
||||
else x->parent->right = y;
|
||||
@ -98,7 +105,7 @@ class RBTree {
|
||||
else root = y;
|
||||
// 3. move y.left to x.right if it exists
|
||||
x->right = y->left;
|
||||
if (x->right != nullptr)
|
||||
if(x->right != null_node_ptr)
|
||||
x->right->parent = x;
|
||||
// 4. move x to y.left
|
||||
y->left = x;
|
||||
@ -110,7 +117,7 @@ class RBTree {
|
||||
Node* y = x->left;
|
||||
// 2. move y up
|
||||
y->parent = x->parent;
|
||||
if (x->parent != nullptr){ // x != root
|
||||
if(x->parent != null_node_ptr){ // x != root
|
||||
if(x == x->parent->left)
|
||||
x->parent->left = y;
|
||||
else x->parent->right = y;
|
||||
@ -118,7 +125,7 @@ class RBTree {
|
||||
else root = y;
|
||||
// 3. move y.right to x.left if it exists
|
||||
x->left = y->right;
|
||||
if (x->left != nullptr)
|
||||
if(x->left != null_node_ptr)
|
||||
x->left->parent = x;
|
||||
// 4. move x to y.right
|
||||
y->right = x;
|
||||
@ -126,128 +133,124 @@ class RBTree {
|
||||
}
|
||||
|
||||
void transplantNode(Node* old, Node* neww){
|
||||
if(old->parent == nullptr)
|
||||
if(old->parent == null_node_ptr)
|
||||
root = neww;
|
||||
else if(old->parent->left == old)
|
||||
old->parent->left = neww;
|
||||
else old->parent->right = neww;
|
||||
if(neww != nullptr)
|
||||
if(neww != null_node_ptr)
|
||||
neww->parent = old->parent;
|
||||
}
|
||||
|
||||
void fixupInsertion(Node* n){
|
||||
// case 1: n is root -- root must be black
|
||||
if (n->parent == nullptr){
|
||||
n->color = Color::Black;
|
||||
return;
|
||||
void fixupInsertion(Node* x){
|
||||
while(x != root && x->parent->color == Color::Red) {
|
||||
if(x->parent == x->parent->parent->left) {
|
||||
Node* y = x->parent->parent->right;
|
||||
// uncle is red
|
||||
if(y->color == Color::Red) {
|
||||
x->parent->color = Color::Black;
|
||||
y->color = Color::Black;
|
||||
x->parent->parent->color = Color::Red;
|
||||
x = x->parent->parent;
|
||||
}
|
||||
|
||||
// case 2: parent is black -- no requirements mismatch
|
||||
if (n->parent->color == Color::Black)
|
||||
return;
|
||||
|
||||
// case 3: parent and uncle are red -- red nodes must have black parents
|
||||
Node* u = n->getUncle();
|
||||
Node* g = n->getGrandparent();
|
||||
if(u != nullptr && u->color == Color::Red){
|
||||
n->parent->color = Color::Black;
|
||||
u->color = Color::Black;
|
||||
g->color = Color::Red;
|
||||
fixupInsertion(g);
|
||||
return;
|
||||
// uncle is black
|
||||
else {
|
||||
if(x == x->parent->right) {
|
||||
// make x a left child
|
||||
x = x->parent;
|
||||
rotateLeft(x);
|
||||
}
|
||||
|
||||
// case 4: parent is red and uncle is black -- red nodes must have black parents
|
||||
if ((n == n->parent->right) && (n->parent == g->left)) {
|
||||
rotateLeft(n->parent);
|
||||
n = n->left;
|
||||
}
|
||||
else if ((n == n->parent->left) && (n->parent == g->right)) {
|
||||
rotateRight(n->parent);
|
||||
n = n->right;
|
||||
}
|
||||
|
||||
// case 5
|
||||
n->parent->color = Color::Black;
|
||||
g->color = Color::Red;
|
||||
if ((n == n->parent->left) && (n->parent == g->left))
|
||||
rotateRight(g);
|
||||
else rotateLeft(g);
|
||||
}
|
||||
|
||||
void fixupDeletion(Node* n){
|
||||
// case 1
|
||||
if(n->parent == nullptr)
|
||||
return;
|
||||
|
||||
// case 2
|
||||
Node* s = n->getSibling();
|
||||
if(s->color == Color::Red){
|
||||
n->parent->color = Color::Red;
|
||||
s->color = Color::Black;
|
||||
if (n == n->parent->left)
|
||||
rotateLeft(n->parent);
|
||||
else rotateRight(n->parent);
|
||||
}
|
||||
|
||||
// case 3
|
||||
if ((n->parent->color == Color::Black) &&
|
||||
(s->color == Color::Black) &&
|
||||
(s->left->color == Color::Black) &&
|
||||
(s->right->color == Color::Black))
|
||||
{
|
||||
s->color = Color::Red;
|
||||
fixupDeletion(n->parent);
|
||||
return;
|
||||
}
|
||||
|
||||
// case 4
|
||||
else if ((n->parent->color == Color::Red) &&
|
||||
(s->color == Color::Black) &&
|
||||
(s->left->color == Color::Black) &&
|
||||
(s->right->color == Color::Black))
|
||||
{
|
||||
s->color = Color::Red;
|
||||
n->parent->color = Color::Black;
|
||||
return;
|
||||
}
|
||||
|
||||
// case 5
|
||||
if(s->color == Color::Black) {
|
||||
if ((n == n->parent->left) &&
|
||||
(s->right->color == Color::Black) &&
|
||||
(s->left->color == Color::Red))
|
||||
{
|
||||
s->color = Color::Red;
|
||||
s->left->color = Color::Black;
|
||||
rotateRight(s);
|
||||
}
|
||||
else if ((n == n->parent->right) &&
|
||||
(s->left->color == Color::Black) &&
|
||||
(s->right->color == Color::Red))
|
||||
{
|
||||
s->color = Color::Red;
|
||||
s->right->color = Color::Black;
|
||||
rotateLeft(s);
|
||||
// recolor and rotate
|
||||
x->parent->color = Color::Black;
|
||||
x->parent->parent->color = Color::Red;
|
||||
rotateRight(x->parent->parent);
|
||||
}
|
||||
}
|
||||
// mirrored above code
|
||||
else {
|
||||
Node* y = x->parent->parent->left;
|
||||
// uncle is red
|
||||
if(y->color == Color::Red) {
|
||||
x->parent->color = Color::Black;
|
||||
y->color = Color::Black;
|
||||
x->parent->parent->color = Color::Red;
|
||||
x = x->parent->parent;
|
||||
}
|
||||
// uncle is black
|
||||
else {
|
||||
if(x == x->parent->left) {
|
||||
// make x a right child
|
||||
x = x->parent;
|
||||
rotateRight(x);
|
||||
}
|
||||
// recolor and rotate
|
||||
x->parent->color = Color::Black;
|
||||
x->parent->parent->color = Color::Red;
|
||||
rotateLeft(x->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
root->color = Color::Black;
|
||||
}
|
||||
|
||||
// case 6
|
||||
s->color = n->parent->color;
|
||||
n->parent->color = Color::Black;
|
||||
|
||||
if (n == n->parent->left) {
|
||||
s->right->color = Color::Black;
|
||||
rotateLeft(n->parent);
|
||||
void fixupDeletion(Node* x){
|
||||
while(x != root && x->color == Color::Black) {
|
||||
if(x == x->parent->left) {
|
||||
Node* w = x->parent->right;
|
||||
if(w->color == Color::Red) {
|
||||
w->color = Color::Black;
|
||||
x->parent->color = Color::Red;
|
||||
rotateLeft(x->parent);
|
||||
w = x->parent->right;
|
||||
}
|
||||
if(w->left->color == Color::Black && w->right->color == Color::Black) {
|
||||
w->color = Color::Red;
|
||||
x = x->parent;
|
||||
} else {
|
||||
s->left->color = Color::Black;
|
||||
rotateRight(n->parent);
|
||||
if(w->right->color == Color::Black) {
|
||||
w->left->color = Color::Black;
|
||||
w->color = Color::Red;
|
||||
rotateRight(w);
|
||||
w = x->parent->right;
|
||||
}
|
||||
w->color = x->parent->color;
|
||||
x->parent->color = Color::Black;
|
||||
w->right->color = Color::Black;
|
||||
rotateLeft(x->parent);
|
||||
x = root;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Node* w = x->parent->left;
|
||||
if(w->color == Color::Red) {
|
||||
w->color = Color::Black;
|
||||
x->parent->color = Color::Red;
|
||||
rotateRight(x->parent);
|
||||
w = x->parent->left;
|
||||
}
|
||||
if(w->right->color == Color::Black && w->left->color == Color::Black) {
|
||||
w->color = Color::Red;
|
||||
x = x->parent;
|
||||
} else {
|
||||
if(w->left->color == Color::Black) {
|
||||
w->right->color = Color::Black;
|
||||
w->color = Color::Red;
|
||||
rotateLeft(w);
|
||||
w = x->parent->left;
|
||||
}
|
||||
w->color = x->parent->color;
|
||||
x->parent->color = Color::Black;
|
||||
w->left->color = Color::Black;
|
||||
rotateRight(x->parent);
|
||||
x = root;
|
||||
}
|
||||
}
|
||||
}
|
||||
x->color = Color::Black;
|
||||
}
|
||||
|
||||
|
||||
template<typename TIteratorValue>
|
||||
struct TreeIterator : std::iterator<std::bidirectional_iterator_tag, TIteratorValue> {
|
||||
template<typename TreeIteratorValue>
|
||||
struct TreeIterator {
|
||||
Node* n;
|
||||
|
||||
TreeIterator(TreeIterator const& src){
|
||||
@ -266,20 +269,20 @@ class RBTree {
|
||||
return n == other.n;
|
||||
}
|
||||
|
||||
TIteratorValue& operator*() const {
|
||||
if(n == nullptr)
|
||||
throw "RBTree::TreeIterator::operator*() error: n == nullptr";
|
||||
return *((TIteratorValue*)(void*)n);
|
||||
TreeIteratorValue& operator*() const {
|
||||
if(!n->isLeaf())
|
||||
return *n;
|
||||
else throw UsefulException("the caller has tried to get the value of the end of an iterator (null node value)");
|
||||
}
|
||||
|
||||
void operator++() {
|
||||
if(n == nullptr)
|
||||
if(n->isLeaf())
|
||||
return;
|
||||
if(n->right)
|
||||
if(!n->right->isLeaf())
|
||||
n = n->right->getMinChild();
|
||||
else {
|
||||
Node* p = n->parent;
|
||||
while(p != nullptr && n == p->right){
|
||||
while(n == p->right){
|
||||
n = p;
|
||||
p = p->parent;
|
||||
}
|
||||
@ -289,20 +292,21 @@ class RBTree {
|
||||
};
|
||||
|
||||
public:
|
||||
using iterator = TreeIterator<std::pair<const TKey, TVal>>;
|
||||
using const_iterator = TreeIterator<std::pair<const TKey, const TVal>>;
|
||||
using iterator = TreeIterator<KVPair>;
|
||||
using const_iterator = TreeIterator<const KVPair>;
|
||||
|
||||
RBTree() {}
|
||||
|
||||
~RBTree(){
|
||||
if(!root->isLeaf())
|
||||
delete root;
|
||||
}
|
||||
|
||||
|
||||
/// @param resultPtr nullable
|
||||
bool tryAdd(TKey key, TVal& value, TVal** resultPtr){
|
||||
if(root == nullptr){
|
||||
root = new Node(key, value, Color::Black, nullptr);
|
||||
if(root == null_node_ptr){
|
||||
root = new Node(key, value, Color::Black, null_node_ptr, null_node_ptr, null_node_ptr);
|
||||
if(resultPtr)
|
||||
*resultPtr = &root->value;
|
||||
return true;
|
||||
@ -316,14 +320,14 @@ public:
|
||||
else nodePtrPtr = &parent->right;
|
||||
|
||||
// if a child node already exists at this place, returns false
|
||||
if(*nodePtrPtr != nullptr){
|
||||
if(*nodePtrPtr != null_node_ptr){
|
||||
if(resultPtr)
|
||||
*resultPtr = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// places newNode to left or right of the parent
|
||||
Node* newNode = new Node(key, value, Color::Red, parent);
|
||||
Node* newNode = new Node(key, value, Color::Red, parent, null_node_ptr, null_node_ptr);
|
||||
if(resultPtr)
|
||||
*resultPtr = &newNode->value;
|
||||
*nodePtrPtr = newNode;
|
||||
@ -340,7 +344,7 @@ public:
|
||||
|
||||
/// @param resultPtr nullable
|
||||
bool trySet(TKey key, TVal& value, TVal** resultPtr){
|
||||
if(root == nullptr){
|
||||
if(root == null_node_ptr){
|
||||
if(resultPtr)
|
||||
*resultPtr = nullptr;
|
||||
return false;
|
||||
@ -354,7 +358,7 @@ public:
|
||||
else nodePtrPtr = &parent->right;
|
||||
|
||||
// if a child node with the given key doesn't exist, returns false
|
||||
if(*nodePtrPtr == nullptr){
|
||||
if(*nodePtrPtr == null_node_ptr){
|
||||
if(resultPtr)
|
||||
*resultPtr = nullptr;
|
||||
return false;
|
||||
@ -375,8 +379,8 @@ public:
|
||||
|
||||
/// @param resultPtr nullable
|
||||
void addOrSet(TKey key, TVal& value, TVal** resultPtr){
|
||||
if(root == nullptr){
|
||||
root = new Node(key, value, Color::Black, nullptr);
|
||||
if(root == null_node_ptr){
|
||||
root = new Node(key, value, Color::Black, null_node_ptr, null_node_ptr, null_node_ptr);
|
||||
if(resultPtr != nullptr)
|
||||
*resultPtr = &root->value;
|
||||
return;
|
||||
@ -390,7 +394,7 @@ public:
|
||||
else nodePtrPtr = &parent->right;
|
||||
|
||||
// if a child node already exists at this place, sets it's value
|
||||
if(*nodePtrPtr != nullptr){
|
||||
if(*nodePtrPtr != null_node_ptr){
|
||||
(*nodePtrPtr)->value = value;
|
||||
if(resultPtr)
|
||||
*resultPtr = &(*nodePtrPtr)->value;
|
||||
@ -398,7 +402,7 @@ public:
|
||||
}
|
||||
|
||||
// places newNode to left or right of the parent
|
||||
Node* newNode = new Node(key, value, Color::Red, parent);
|
||||
Node* newNode = new Node(key, value, Color::Red, parent, null_node_ptr, null_node_ptr);
|
||||
if(resultPtr != nullptr)
|
||||
*resultPtr = &newNode->value;
|
||||
*nodePtrPtr = newNode;
|
||||
@ -416,14 +420,14 @@ public:
|
||||
if(!resultPtr)
|
||||
return false;
|
||||
Node* parent = findParentForKey(key);
|
||||
Node* n = nullptr;
|
||||
if(parent == nullptr)
|
||||
Node* n = null_node_ptr;
|
||||
if(parent == null_node_ptr)
|
||||
n = root;
|
||||
else if(key < parent->key)
|
||||
n = parent->left;
|
||||
else n = parent->right;
|
||||
// if there is no node with the given key
|
||||
if(n == nullptr){
|
||||
if(n == null_node_ptr){
|
||||
*resultPtr = nullptr;
|
||||
return false;
|
||||
}
|
||||
@ -435,25 +439,25 @@ public:
|
||||
|
||||
bool tryDelete(TKey key){
|
||||
Node* parent = findParentForKey(key);
|
||||
Node* n = nullptr;
|
||||
if(parent == nullptr)
|
||||
Node* n = null_node_ptr;
|
||||
if(parent == null_node_ptr)
|
||||
n = root;
|
||||
else if(key < parent->key)
|
||||
n = parent->left;
|
||||
else n = parent->right;
|
||||
// key not found
|
||||
if(n == nullptr){
|
||||
if(n == null_node_ptr){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(n->left == nullptr){
|
||||
if(n->left == null_node_ptr){
|
||||
transplantNode(n, n->right);
|
||||
if(n->color == Color::Black && n->right != nullptr)
|
||||
if(n->color == Color::Black && n->right != null_node_ptr)
|
||||
fixupDeletion(n->right);
|
||||
}
|
||||
else if(n->right == nullptr){
|
||||
else if(n->right == null_node_ptr){
|
||||
transplantNode(n, n->left);
|
||||
if(n->color == Color::Black && n->left != nullptr)
|
||||
if(n->color == Color::Black && n->left != null_node_ptr)
|
||||
fixupDeletion(n->left);
|
||||
}
|
||||
else {
|
||||
@ -471,55 +475,63 @@ public:
|
||||
fixupDeletion(minNode->right);
|
||||
}
|
||||
|
||||
// delete node without children
|
||||
n->left = null_node_ptr;
|
||||
n->right = null_node_ptr;
|
||||
delete n;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
iterator begin(){
|
||||
if(root == nullptr)
|
||||
return iterator(nullptr);
|
||||
if(root == null_node_ptr)
|
||||
return iterator(null_node_ptr);
|
||||
return iterator(root->getMinChild());
|
||||
}
|
||||
|
||||
iterator end(){
|
||||
if(root == nullptr)
|
||||
return iterator(nullptr);
|
||||
return iterator(root->getMaxChild());
|
||||
return iterator(null_node_ptr);
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if(root == nullptr)
|
||||
return const_iterator(nullptr);
|
||||
if(root == null_node_ptr)
|
||||
return const_iterator(null_node_ptr);
|
||||
return const_iterator(root->getMinChild());
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator(nullptr);
|
||||
return const_iterator(null_node_ptr);
|
||||
}
|
||||
|
||||
void _generateGraphVizCodeForChildren(std::stringstream& ss, Node* n) const {
|
||||
if(!n)
|
||||
if(n == null_node_ptr)
|
||||
return;
|
||||
|
||||
if(n->color == Color::Red)
|
||||
ss<<" \""<<n->key<<"\" [color=red]\n";
|
||||
if(n->left){
|
||||
|
||||
if(n->left == null_node_ptr){
|
||||
ss<<" \""<<n->key<<"\" -> \"null\" [side=L]\n";
|
||||
}
|
||||
else {
|
||||
ss<<" \""<<n->key<<"\" -> \""<<n->left->key<<"\" [side=L]\n";
|
||||
_generateGraphVizCodeForChildren(ss, n->left);
|
||||
}
|
||||
else ss<<" \""<<n->key<<"\" -> \"null\" [side=L]\n";
|
||||
if(n->right){
|
||||
|
||||
if(n->right == null_node_ptr){
|
||||
ss<<" \""<<n->key<<"\" -> \"null\" [side=R]\n";
|
||||
}
|
||||
else {
|
||||
ss<<" \""<<n->key<<"\" -> \""<<n->right->key<<"\" [side=R]\n";
|
||||
_generateGraphVizCodeForChildren(ss, n->right);
|
||||
}
|
||||
else ss<<" \""<<n->key<<"\" -> \"null\" [side=R]\n";
|
||||
}
|
||||
|
||||
std::string generateGraphVizCode() const {
|
||||
std::stringstream ss;
|
||||
ss<<"digraph {\n"
|
||||
" node [style=filled,color=gray];\n";
|
||||
if(root == nullptr)
|
||||
if(root == null_node_ptr)
|
||||
ss<<" \"null\"\n";
|
||||
else {
|
||||
ss<<" \"null-parent\" -> \""<<root->key<<"\"\n";
|
||||
@ -529,3 +541,10 @@ public:
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename TKey, typename TVal>
|
||||
typename RBTree<TKey, TVal>::Node RBTree<TKey, TVal>::null_node;
|
||||
|
||||
template<typename TKey, typename TVal>
|
||||
typename RBTree<TKey, TVal>::Node* RBTree<TKey, TVal>::null_node_ptr = &RBTree<TKey, TVal>::null_node;
|
||||
|
||||
@ -11,7 +11,7 @@ void GraphEditor::drawNode(const GraphModel::Node& node){
|
||||
ImNodes::EndNodeTitleBar();
|
||||
|
||||
for(auto& a_p : node.getAttributes()){
|
||||
auto&& a = *a_p.second;
|
||||
auto&& a = *a_p.value;
|
||||
switch (a.type){
|
||||
case GraphModel::Attribute::Type::Input:
|
||||
ImNodes::BeginInputAttribute(a.id);
|
||||
@ -140,11 +140,11 @@ void GraphEditor::draw(){
|
||||
ImNodes::BeginNodeEditor();
|
||||
// draw nodes
|
||||
for(auto& n_p : graph.getNodes()){
|
||||
drawNode(n_p.second);
|
||||
drawNode(n_p.value);
|
||||
}
|
||||
// draw edges
|
||||
for(auto& p : graph.getEdges()){
|
||||
ImNodes::Link(p.second.id, p.second.to_attr_id, p.second.from_attr_id);
|
||||
ImNodes::Link(p.value.id, p.value.to_attr_id, p.value.from_attr_id);
|
||||
}
|
||||
|
||||
ImNodes::EndNodeEditor();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user