Mercurial > dedupe
diff RBTree.hpp @ 16:06166d6c083b
Add configuration processing.
Cache DB values
Add a custom RBTree to save space.
Track multiple DB connections properly.
More testing.
Add ValueExistsException.
| author | Tom Fredrik Blenning Klaussen <bfg@blenning.no> |
|---|---|
| date | Tue, 28 Aug 2012 18:58:02 +0200 |
| parents | |
| children | 9a1825df8418 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RBTree.hpp Tue Aug 28 18:58:02 2012 +0200 @@ -0,0 +1,344 @@ +#ifndef RBTREE_HPP +#define RBTREE_HPP + +#include <boost/optional.hpp> +#include <cmath> +#include "ValueExistsException.hpp" + +#include <QtCore/QDebug> + +#define CONSISTENCY_CHECKING 0 + +#if CONSISTENCY_CHECKING +#define CONSISTENCY_CHECK(n) assert(!n || (n)->consistent()) +#else +#define CONSISTENCY_CHECK(n) +#endif + +template<typename Data> +class RBTree { +private: + class RBTreeNode { + Data data; + RBTreeNode* left; + RBTreeNode *right; + RBTreeNode *parent; + bool red; + + enum Color { RED, BLACK }; + + public: + RBTreeNode(const Data& data) : left(0), right(0), parent(0), red(true) + { + this->data = data; + } + + void setColor(Color color) + { + red = (color == RED); + } + + Color color() const + { + return red ? RED : BLACK; + } + + RBTreeNode* grandparent() + { + if ((this != NULL) && (this->parent != NULL)) + return this->parent->parent; + else + return NULL; + } + + RBTreeNode* uncle() + { + RBTreeNode* g = grandparent(); + if (g == NULL) + return NULL; // No grandparent means no uncle + if (this->parent == g->left) + return g->right; + else + return g->left; + } + + RBTreeNode* getRootNode() + { + RBTreeNode* p = this; + while(p->parent) + p = p->parent; + return p; + } + + void rotate_left() + { + RBTreeNode* Q = this->right; + assert(Q); + // Set Q to be the new root. + if (this->parent) { + if (this->parent->left == this) { + this->parent->left = Q; + } + else { + assert(this->parent->right == this); + this->parent->right = Q; + } + } + this->right = Q->left; + if (this->right) + this->right->parent = this; + Q->left = this; + Q->parent = this->parent; + this->parent = Q; + } + + void rotate_right() + { + RBTreeNode* P = this->left; + assert(P); + //Set P to be the new root. + if (this->parent) { + if (this->parent->left == this) { + this->parent->left = P; + } + else { + assert(this->parent->right == this); + this->parent->right = P; + } + } + this->left = P->right; + if (this->left) + this->left->parent = this; + P->right = this; + P->parent = this->parent; + this->parent = P; + } + + void insert_case5() + { + RBTreeNode* g = grandparent(); + CONSISTENCY_CHECK(this); + CONSISTENCY_CHECK(g); + + this->parent->setColor(BLACK); + g->setColor(RED); + if (this == this->parent->left) + g->rotate_right(); + else { + assert (this == this->parent->right); + g->rotate_left(); + } + } + + void insert_case4() + { + RBTreeNode* g = grandparent(); + + CONSISTENCY_CHECK(this); + + if (!g) + return; + CONSISTENCY_CHECK(g); + + RBTreeNode* n = this; + + if ((this == n->parent->right) && (n->parent == g->left)) { + n->parent->rotate_left(); + n = n->left; + } else if ((n == n->parent->left) && (n->parent == g->right)) { + n->parent->rotate_right(); + n = n->right; + } + n->insert_case5(); + } + + + void insert_case3() + { + RBTreeNode *u = uncle(); + CONSISTENCY_CHECK(this); + CONSISTENCY_CHECK(u); + + if ((u != NULL) && (u->color() == RED)) { + this->parent->setColor(BLACK); + u->setColor(BLACK); + RBTreeNode* g; + g = grandparent(); + g->setColor(RED); + g->insert_case1(); + } else { + insert_case4(); + } + } + + void insert_case2() + { + CONSISTENCY_CHECK(this); + if (this->parent->color() == BLACK) + return; /* Tree is still valid */ + else + insert_case3(); + } + + void insert_case1() + { + CONSISTENCY_CHECK(this); + + if (this->parent == NULL) + this->setColor(BLACK); + else + insert_case2(); + } + + void insert(const Data& data) + { + if (data < this->data) { + if (!left) { + left = new RBTreeNode(data); + left->parent = this; + left->insert_case1(); + } + else + left->insert(data); + } + else if (data > this->data) { + if (!right) { + right = new RBTreeNode(data); + right->parent = this; + right->insert_case1(); + } + else + right->insert(data); + } + else { + throw ValueExistsException(); + } + CONSISTENCY_CHECK(this); + } + + boost::optional<Data> find(const Data& data) + { + if (this->data == data) { + return this->data; + } + else if (data < this->data) { + if (left) + return left->find(data); + else + return boost::optional<Data>(); + } + else { + if (right) + return right->find(data); + else + return boost::optional<Data>(); + } + return boost::optional<Data>(); + } + + uint size() const + { + return 1 + (left ? left->size() : 0) + (right ? right->size() : 0); + } + + uint depth() const + { + return 1 + std::max((left ? left->depth() : 0), (right ? right->depth() : 0)); + } + + uint total_depth(uint n) const + { + return n + (left ? left->total_depth(n + 1) : 0) + (right ? right->total_depth(n + 1) : 0); + } + + bool consistent() const + { + bool retVal = true; + if (left) + retVal = retVal && (left->parent == this) && left->consistent(); + if (right) + retVal = retVal && (right->parent == this) && right->consistent(); + return retVal; + } + + friend class RBTree; + + }; + RBTreeNode* node; +public: + RBTree() : node(0) + { + } + + bool consistent() const + { + if (node == 0) + return true; + if (node->parent == 0 && node->consistent()) + return true; + return false; + } + + void insert(const Data& data) + { + if (node == 0) { + node = new RBTreeNode(data); + } + else { + node->insert(data); + } + node = node->getRootNode(); + CONSISTENCY_CHECK(this); + } + boost::optional<Data> find(const Data& data) + { + if (node) { + return node->find(data); + } + else + return boost::optional<Data>(); + } + + uint size() const + { + if (!node) + return 0; + else + return node->size(); + } + + uint depth() const + { + if (!node) + return 0; + return node->depth(); + } + + float avg_depth() const + { + if (!node) + return 0; + return double(total_depth())/size(); + } + + uint total_depth() const + { + if (!node) + return 0; + return node->total_depth(1); + } + + uint optimal_depth() const + { + int s = size(); + if (s == 0) + return 0; + int d = s; + int targetlevel = 1; + while (d >>= 1) + ++targetlevel; + return targetlevel; + } +}; + +#endif //RBTREE_HPP
