RBTree implementation with const null_node

This commit is contained in:
Timerix22 2024-05-06 16:18:11 +05:00
parent 2050eb4d46
commit da1dfd4c13
7 changed files with 246 additions and 210 deletions

View File

@ -2,10 +2,14 @@
namespace GraphC::GraphModel { namespace GraphC::GraphModel {
Attribute::Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title) Attribute::Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title)
: type(_type), id(_id), parent_node(_parent_node), title(_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 { const RBTree<id_t, Edge*>& Attribute::getIncomingEdges() const {
return incoming_edges; return incoming_edges;
} }

View File

@ -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) : 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)
{}
} }

View File

@ -32,7 +32,7 @@ bool Graph::tryGetNode(id_t node_id, Node** result) const {
void Graph::deleteNode(Node& n){ void Graph::deleteNode(Node& n){
for(const auto& attr_p : n.attributes) for(const auto& attr_p : n.attributes)
deleteAttribute(*attr_p.second); deleteAttribute(*attr_p.value);
useful_assert(nodes.tryDelete(n.id), useful_assert(nodes.tryDelete(n.id),
format("can't delete node with id %i", 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){ void Graph::deleteAttribute(Attribute& a){
for(const auto& edge_p : a.incoming_edges){ for(const auto& edge_p : a.incoming_edges){
useful_assert(edges.tryDelete(edge_p.second->id), useful_assert(edges.tryDelete(edge_p.value->id),
format("can't find edge with id %i", edge_p.second->id)); format("can't find edge with id %i", edge_p.value->id));
} }
for(const auto& edge_p : a.outgoing_edges){ for(const auto& edge_p : a.outgoing_edges){
useful_assert(edges.tryDelete(edge_p.second->id), useful_assert(edges.tryDelete(edge_p.value->id),
format("can't find edge with id %i", edge_p.second->id)); format("can't find edge with id %i", edge_p.value->id));
} }
useful_assert(attributes.tryDelete(a.id), useful_assert(attributes.tryDelete(a.id),
format("can't delete attribute with id %i", a.id)); format("can't delete attribute with id %i", a.id));

View File

@ -9,6 +9,7 @@
namespace GraphC::GraphModel { namespace GraphC::GraphModel {
typedef i32 id_t; typedef i32 id_t;
#define id_t_invalid ((id_t)-1)
class IdGenerator { class IdGenerator {
id_t next_id=1; id_t next_id=1;
@ -39,6 +40,8 @@ public:
Node *const parent_node; Node *const parent_node;
std::string title; 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); Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title);
const RBTree<id_t, Edge*>& getIncomingEdges() const; const RBTree<id_t, Edge*>& getIncomingEdges() const;
@ -54,6 +57,8 @@ public:
const id_t id; const id_t id;
std::string title; std::string title;
///@warning empty constructor for RBTree null-value node, do not use it
Node();
Node(id_t _id, std::string _title); Node(id_t _id, std::string _title);
const RBTree<id_t, Attribute*>& getAttributes() const; const RBTree<id_t, Attribute*>& getAttributes() const;
@ -64,6 +69,8 @@ struct Edge {
const id_t to_attr_id; const id_t to_attr_id;
const id_t from_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); Edge(id_t _id, id_t _from_attr_id, id_t _to_attr_id);
}; };

View File

@ -6,6 +6,9 @@ Node::Node(id_t _id, std::string _title)
: id(_id), title(_title) : id(_id), title(_title)
{} {}
Node::Node() : Node(id_t_invalid, "NULL_NODE")
{}
const RBTree<id_t, Attribute*>& Node::getAttributes() const { const RBTree<id_t, Attribute*>& Node::getAttributes() const {
return attributes; return attributes;
} }

View File

@ -1,80 +1,87 @@
#pragma once #pragma once
#include "../../dependencies/kerep/src/base/base.h"
#include <map>
#include <sstream> #include <sstream>
#include "UsefulException.hpp"
// typedef char* TKey;
// typedef char* TVal;
template<typename TKey, typename TVal> template<typename TKey, typename TVal>
class RBTree { class RBTree {
enum class Color { enum class Color {
Red, Black Red, Black
}; };
struct Node { // public version of struct Node
TKey key; // 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; 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; Color color;
Node* parent; Node* parent;
Node* left = nullptr; Node* left;
Node* right = nullptr; Node* right;
Node(TKey _key, TVal _val, Color _color, Node* _parent) Node(TKey& _key, TVal& _val, Color _color, Node* _parent, Node* _left, Node* _right)
: key(_key), value(_val), color(_color), parent(_parent) : 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(){ ~Node(){
if(!left->isLeaf())
delete left; delete left;
if(!right->isLeaf())
delete right; delete right;
} }
inline Node* getSibling(){ /// if is leaf returns itself
if(parent == nullptr) Node* getMinChild() {
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(){
Node* n = this; Node* n = this;
while(n->left != nullptr) while(!n->left->isLeaf())
n = n->left; n = n->left;
return n; return n;
} }
// n should be not null /// if is leaf returns itself
Node* getMaxChild(){ Node* getMaxChild() {
Node* n = this; Node* n = this;
while(n->right != nullptr) while(!n->right->isLeaf())
n = n->right; n = n->right;
return n; return n;
} }
}; };
Node* root = nullptr; static Node null_node;
static Node* null_node_ptr;
Node* root = &null_node;
///@returns null if root is null ///@returns null if root is null
Node* findParentForKey(TKey key) const { Node* findParentForKey(TKey key) const {
Node* n = root; Node* n = root;
Node* parent = nullptr; Node* parent = null_node_ptr;
while(n != nullptr){ while(n != null_node_ptr){
parent = n; parent = n;
if(key < n->key) if(key < n->key)
n = n->left; n = n->left;
@ -90,7 +97,7 @@ class RBTree {
Node* y = x->right; Node* y = x->right;
// 2. move y to the position of x // 2. move y to the position of x
y->parent = x->parent; y->parent = x->parent;
if (x->parent != nullptr){ // x != root if(x->parent != null_node_ptr){ // x != root
if(x == x->parent->left) if(x == x->parent->left)
x->parent->left = y; x->parent->left = y;
else x->parent->right = y; else x->parent->right = y;
@ -98,7 +105,7 @@ class RBTree {
else root = y; else root = y;
// 3. move y.left to x.right if it exists // 3. move y.left to x.right if it exists
x->right = y->left; x->right = y->left;
if (x->right != nullptr) if(x->right != null_node_ptr)
x->right->parent = x; x->right->parent = x;
// 4. move x to y.left // 4. move x to y.left
y->left = x; y->left = x;
@ -110,7 +117,7 @@ class RBTree {
Node* y = x->left; Node* y = x->left;
// 2. move y up // 2. move y up
y->parent = x->parent; y->parent = x->parent;
if (x->parent != nullptr){ // x != root if(x->parent != null_node_ptr){ // x != root
if(x == x->parent->left) if(x == x->parent->left)
x->parent->left = y; x->parent->left = y;
else x->parent->right = y; else x->parent->right = y;
@ -118,7 +125,7 @@ class RBTree {
else root = y; else root = y;
// 3. move y.right to x.left if it exists // 3. move y.right to x.left if it exists
x->left = y->right; x->left = y->right;
if (x->left != nullptr) if(x->left != null_node_ptr)
x->left->parent = x; x->left->parent = x;
// 4. move x to y.right // 4. move x to y.right
y->right = x; y->right = x;
@ -126,128 +133,124 @@ class RBTree {
} }
void transplantNode(Node* old, Node* neww){ void transplantNode(Node* old, Node* neww){
if(old->parent == nullptr) if(old->parent == null_node_ptr)
root = neww; root = neww;
else if(old->parent->left == old) else if(old->parent->left == old)
old->parent->left = neww; old->parent->left = neww;
else old->parent->right = neww; else old->parent->right = neww;
if(neww != nullptr) if(neww != null_node_ptr)
neww->parent = old->parent; neww->parent = old->parent;
} }
void fixupInsertion(Node* n){ void fixupInsertion(Node* x){
// case 1: n is root -- root must be black while(x != root && x->parent->color == Color::Red) {
if (n->parent == nullptr){ if(x->parent == x->parent->parent->left) {
n->color = Color::Black; Node* y = x->parent->parent->right;
return; // 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
// case 2: parent is black -- no requirements mismatch else {
if (n->parent->color == Color::Black) if(x == x->parent->right) {
return; // make x a left child
x = x->parent;
// case 3: parent and uncle are red -- red nodes must have black parents rotateLeft(x);
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;
} }
// recolor and rotate
// case 4: parent is red and uncle is black -- red nodes must have black parents x->parent->color = Color::Black;
if ((n == n->parent->right) && (n->parent == g->left)) { x->parent->parent->color = Color::Red;
rotateLeft(n->parent); rotateRight(x->parent->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);
} }
} }
// 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 void fixupDeletion(Node* x){
s->color = n->parent->color; while(x != root && x->color == Color::Black) {
n->parent->color = Color::Black; if(x == x->parent->left) {
Node* w = x->parent->right;
if (n == n->parent->left) { if(w->color == Color::Red) {
s->right->color = Color::Black; w->color = Color::Black;
rotateLeft(n->parent); 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 { } else {
s->left->color = Color::Black; if(w->right->color == Color::Black) {
rotateRight(n->parent); 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 TreeIteratorValue>
template<typename TIteratorValue> struct TreeIterator {
struct TreeIterator : std::iterator<std::bidirectional_iterator_tag, TIteratorValue> {
Node* n; Node* n;
TreeIterator(TreeIterator const& src){ TreeIterator(TreeIterator const& src){
@ -266,20 +269,20 @@ class RBTree {
return n == other.n; return n == other.n;
} }
TIteratorValue& operator*() const { TreeIteratorValue& operator*() const {
if(n == nullptr) if(!n->isLeaf())
throw "RBTree::TreeIterator::operator*() error: n == nullptr"; return *n;
return *((TIteratorValue*)(void*)n); else throw UsefulException("the caller has tried to get the value of the end of an iterator (null node value)");
} }
void operator++() { void operator++() {
if(n == nullptr) if(n->isLeaf())
return; return;
if(n->right) if(!n->right->isLeaf())
n = n->right->getMinChild(); n = n->right->getMinChild();
else { else {
Node* p = n->parent; Node* p = n->parent;
while(p != nullptr && n == p->right){ while(n == p->right){
n = p; n = p;
p = p->parent; p = p->parent;
} }
@ -289,20 +292,21 @@ class RBTree {
}; };
public: public:
using iterator = TreeIterator<std::pair<const TKey, TVal>>; using iterator = TreeIterator<KVPair>;
using const_iterator = TreeIterator<std::pair<const TKey, const TVal>>; using const_iterator = TreeIterator<const KVPair>;
RBTree() {} RBTree() {}
~RBTree(){ ~RBTree(){
if(!root->isLeaf())
delete root; delete root;
} }
/// @param resultPtr nullable /// @param resultPtr nullable
bool tryAdd(TKey key, TVal& value, TVal** resultPtr){ bool tryAdd(TKey key, TVal& value, TVal** resultPtr){
if(root == nullptr){ if(root == null_node_ptr){
root = new Node(key, value, Color::Black, nullptr); root = new Node(key, value, Color::Black, null_node_ptr, null_node_ptr, null_node_ptr);
if(resultPtr) if(resultPtr)
*resultPtr = &root->value; *resultPtr = &root->value;
return true; return true;
@ -316,14 +320,14 @@ public:
else nodePtrPtr = &parent->right; else nodePtrPtr = &parent->right;
// if a child node already exists at this place, returns false // if a child node already exists at this place, returns false
if(*nodePtrPtr != nullptr){ if(*nodePtrPtr != null_node_ptr){
if(resultPtr) if(resultPtr)
*resultPtr = nullptr; *resultPtr = nullptr;
return false; return false;
} }
// places newNode to left or right of the parent // 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) if(resultPtr)
*resultPtr = &newNode->value; *resultPtr = &newNode->value;
*nodePtrPtr = newNode; *nodePtrPtr = newNode;
@ -340,7 +344,7 @@ public:
/// @param resultPtr nullable /// @param resultPtr nullable
bool trySet(TKey key, TVal& value, TVal** resultPtr){ bool trySet(TKey key, TVal& value, TVal** resultPtr){
if(root == nullptr){ if(root == null_node_ptr){
if(resultPtr) if(resultPtr)
*resultPtr = nullptr; *resultPtr = nullptr;
return false; return false;
@ -354,7 +358,7 @@ public:
else nodePtrPtr = &parent->right; else nodePtrPtr = &parent->right;
// if a child node with the given key doesn't exist, returns false // if a child node with the given key doesn't exist, returns false
if(*nodePtrPtr == nullptr){ if(*nodePtrPtr == null_node_ptr){
if(resultPtr) if(resultPtr)
*resultPtr = nullptr; *resultPtr = nullptr;
return false; return false;
@ -375,8 +379,8 @@ public:
/// @param resultPtr nullable /// @param resultPtr nullable
void addOrSet(TKey key, TVal& value, TVal** resultPtr){ void addOrSet(TKey key, TVal& value, TVal** resultPtr){
if(root == nullptr){ if(root == null_node_ptr){
root = new Node(key, value, Color::Black, nullptr); root = new Node(key, value, Color::Black, null_node_ptr, null_node_ptr, null_node_ptr);
if(resultPtr != nullptr) if(resultPtr != nullptr)
*resultPtr = &root->value; *resultPtr = &root->value;
return; return;
@ -390,7 +394,7 @@ public:
else nodePtrPtr = &parent->right; else nodePtrPtr = &parent->right;
// if a child node already exists at this place, sets it's value // if a child node already exists at this place, sets it's value
if(*nodePtrPtr != nullptr){ if(*nodePtrPtr != null_node_ptr){
(*nodePtrPtr)->value = value; (*nodePtrPtr)->value = value;
if(resultPtr) if(resultPtr)
*resultPtr = &(*nodePtrPtr)->value; *resultPtr = &(*nodePtrPtr)->value;
@ -398,7 +402,7 @@ public:
} }
// places newNode to left or right of the parent // 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) if(resultPtr != nullptr)
*resultPtr = &newNode->value; *resultPtr = &newNode->value;
*nodePtrPtr = newNode; *nodePtrPtr = newNode;
@ -416,14 +420,14 @@ public:
if(!resultPtr) if(!resultPtr)
return false; return false;
Node* parent = findParentForKey(key); Node* parent = findParentForKey(key);
Node* n = nullptr; Node* n = null_node_ptr;
if(parent == nullptr) if(parent == null_node_ptr)
n = root; n = root;
else if(key < parent->key) else if(key < parent->key)
n = parent->left; n = parent->left;
else n = parent->right; else n = parent->right;
// if there is no node with the given key // if there is no node with the given key
if(n == nullptr){ if(n == null_node_ptr){
*resultPtr = nullptr; *resultPtr = nullptr;
return false; return false;
} }
@ -435,25 +439,25 @@ public:
bool tryDelete(TKey key){ bool tryDelete(TKey key){
Node* parent = findParentForKey(key); Node* parent = findParentForKey(key);
Node* n = nullptr; Node* n = null_node_ptr;
if(parent == nullptr) if(parent == null_node_ptr)
n = root; n = root;
else if(key < parent->key) else if(key < parent->key)
n = parent->left; n = parent->left;
else n = parent->right; else n = parent->right;
// key not found // key not found
if(n == nullptr){ if(n == null_node_ptr){
return false; return false;
} }
if(n->left == nullptr){ if(n->left == null_node_ptr){
transplantNode(n, n->right); 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); fixupDeletion(n->right);
} }
else if(n->right == nullptr){ else if(n->right == null_node_ptr){
transplantNode(n, n->left); 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); fixupDeletion(n->left);
} }
else { else {
@ -471,55 +475,63 @@ public:
fixupDeletion(minNode->right); fixupDeletion(minNode->right);
} }
// delete node without children
n->left = null_node_ptr;
n->right = null_node_ptr;
delete n; delete n;
return true; return true;
} }
iterator begin(){ iterator begin(){
if(root == nullptr) if(root == null_node_ptr)
return iterator(nullptr); return iterator(null_node_ptr);
return iterator(root->getMinChild()); return iterator(root->getMinChild());
} }
iterator end(){ iterator end(){
if(root == nullptr) return iterator(null_node_ptr);
return iterator(nullptr);
return iterator(root->getMaxChild());
} }
const_iterator begin() const { const_iterator begin() const {
if(root == nullptr) if(root == null_node_ptr)
return const_iterator(nullptr); return const_iterator(null_node_ptr);
return const_iterator(root->getMinChild()); return const_iterator(root->getMinChild());
} }
const_iterator end() const { const_iterator end() const {
return const_iterator(nullptr); return const_iterator(null_node_ptr);
} }
void _generateGraphVizCodeForChildren(std::stringstream& ss, Node* n) const { void _generateGraphVizCodeForChildren(std::stringstream& ss, Node* n) const {
if(!n) if(n == null_node_ptr)
return; return;
if(n->color == Color::Red) if(n->color == Color::Red)
ss<<" \""<<n->key<<"\" [color=red]\n"; 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"; ss<<" \""<<n->key<<"\" -> \""<<n->left->key<<"\" [side=L]\n";
_generateGraphVizCodeForChildren(ss, n->left); _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"; ss<<" \""<<n->key<<"\" -> \""<<n->right->key<<"\" [side=R]\n";
_generateGraphVizCodeForChildren(ss, n->right); _generateGraphVizCodeForChildren(ss, n->right);
} }
else ss<<" \""<<n->key<<"\" -> \"null\" [side=R]\n";
} }
std::string generateGraphVizCode() const { std::string generateGraphVizCode() const {
std::stringstream ss; std::stringstream ss;
ss<<"digraph {\n" ss<<"digraph {\n"
" node [style=filled,color=gray];\n"; " node [style=filled,color=gray];\n";
if(root == nullptr) if(root == null_node_ptr)
ss<<" \"null\"\n"; ss<<" \"null\"\n";
else { else {
ss<<" \"null-parent\" -> \""<<root->key<<"\"\n"; ss<<" \"null-parent\" -> \""<<root->key<<"\"\n";
@ -529,3 +541,10 @@ public:
return ss.str(); 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;

View File

@ -11,7 +11,7 @@ void GraphEditor::drawNode(const GraphModel::Node& node){
ImNodes::EndNodeTitleBar(); ImNodes::EndNodeTitleBar();
for(auto& a_p : node.getAttributes()){ for(auto& a_p : node.getAttributes()){
auto&& a = *a_p.second; auto&& a = *a_p.value;
switch (a.type){ switch (a.type){
case GraphModel::Attribute::Type::Input: case GraphModel::Attribute::Type::Input:
ImNodes::BeginInputAttribute(a.id); ImNodes::BeginInputAttribute(a.id);
@ -140,11 +140,11 @@ void GraphEditor::draw(){
ImNodes::BeginNodeEditor(); ImNodes::BeginNodeEditor();
// draw nodes // draw nodes
for(auto& n_p : graph.getNodes()){ for(auto& n_p : graph.getNodes()){
drawNode(n_p.second); drawNode(n_p.value);
} }
// draw edges // draw edges
for(auto& p : graph.getEdges()){ 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(); ImNodes::EndNodeEditor();