comparison 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
comparison
equal deleted inserted replaced
15:199fc63c60c1 16:06166d6c083b
1 #ifndef RBTREE_HPP
2 #define RBTREE_HPP
3
4 #include <boost/optional.hpp>
5 #include <cmath>
6 #include "ValueExistsException.hpp"
7
8 #include <QtCore/QDebug>
9
10 #define CONSISTENCY_CHECKING 0
11
12 #if CONSISTENCY_CHECKING
13 #define CONSISTENCY_CHECK(n) assert(!n || (n)->consistent())
14 #else
15 #define CONSISTENCY_CHECK(n)
16 #endif
17
18 template<typename Data>
19 class RBTree {
20 private:
21 class RBTreeNode {
22 Data data;
23 RBTreeNode* left;
24 RBTreeNode *right;
25 RBTreeNode *parent;
26 bool red;
27
28 enum Color { RED, BLACK };
29
30 public:
31 RBTreeNode(const Data& data) : left(0), right(0), parent(0), red(true)
32 {
33 this->data = data;
34 }
35
36 void setColor(Color color)
37 {
38 red = (color == RED);
39 }
40
41 Color color() const
42 {
43 return red ? RED : BLACK;
44 }
45
46 RBTreeNode* grandparent()
47 {
48 if ((this != NULL) && (this->parent != NULL))
49 return this->parent->parent;
50 else
51 return NULL;
52 }
53
54 RBTreeNode* uncle()
55 {
56 RBTreeNode* g = grandparent();
57 if (g == NULL)
58 return NULL; // No grandparent means no uncle
59 if (this->parent == g->left)
60 return g->right;
61 else
62 return g->left;
63 }
64
65 RBTreeNode* getRootNode()
66 {
67 RBTreeNode* p = this;
68 while(p->parent)
69 p = p->parent;
70 return p;
71 }
72
73 void rotate_left()
74 {
75 RBTreeNode* Q = this->right;
76 assert(Q);
77 // Set Q to be the new root.
78 if (this->parent) {
79 if (this->parent->left == this) {
80 this->parent->left = Q;
81 }
82 else {
83 assert(this->parent->right == this);
84 this->parent->right = Q;
85 }
86 }
87 this->right = Q->left;
88 if (this->right)
89 this->right->parent = this;
90 Q->left = this;
91 Q->parent = this->parent;
92 this->parent = Q;
93 }
94
95 void rotate_right()
96 {
97 RBTreeNode* P = this->left;
98 assert(P);
99 //Set P to be the new root.
100 if (this->parent) {
101 if (this->parent->left == this) {
102 this->parent->left = P;
103 }
104 else {
105 assert(this->parent->right == this);
106 this->parent->right = P;
107 }
108 }
109 this->left = P->right;
110 if (this->left)
111 this->left->parent = this;
112 P->right = this;
113 P->parent = this->parent;
114 this->parent = P;
115 }
116
117 void insert_case5()
118 {
119 RBTreeNode* g = grandparent();
120 CONSISTENCY_CHECK(this);
121 CONSISTENCY_CHECK(g);
122
123 this->parent->setColor(BLACK);
124 g->setColor(RED);
125 if (this == this->parent->left)
126 g->rotate_right();
127 else {
128 assert (this == this->parent->right);
129 g->rotate_left();
130 }
131 }
132
133 void insert_case4()
134 {
135 RBTreeNode* g = grandparent();
136
137 CONSISTENCY_CHECK(this);
138
139 if (!g)
140 return;
141 CONSISTENCY_CHECK(g);
142
143 RBTreeNode* n = this;
144
145 if ((this == n->parent->right) && (n->parent == g->left)) {
146 n->parent->rotate_left();
147 n = n->left;
148 } else if ((n == n->parent->left) && (n->parent == g->right)) {
149 n->parent->rotate_right();
150 n = n->right;
151 }
152 n->insert_case5();
153 }
154
155
156 void insert_case3()
157 {
158 RBTreeNode *u = uncle();
159 CONSISTENCY_CHECK(this);
160 CONSISTENCY_CHECK(u);
161
162 if ((u != NULL) && (u->color() == RED)) {
163 this->parent->setColor(BLACK);
164 u->setColor(BLACK);
165 RBTreeNode* g;
166 g = grandparent();
167 g->setColor(RED);
168 g->insert_case1();
169 } else {
170 insert_case4();
171 }
172 }
173
174 void insert_case2()
175 {
176 CONSISTENCY_CHECK(this);
177 if (this->parent->color() == BLACK)
178 return; /* Tree is still valid */
179 else
180 insert_case3();
181 }
182
183 void insert_case1()
184 {
185 CONSISTENCY_CHECK(this);
186
187 if (this->parent == NULL)
188 this->setColor(BLACK);
189 else
190 insert_case2();
191 }
192
193 void insert(const Data& data)
194 {
195 if (data < this->data) {
196 if (!left) {
197 left = new RBTreeNode(data);
198 left->parent = this;
199 left->insert_case1();
200 }
201 else
202 left->insert(data);
203 }
204 else if (data > this->data) {
205 if (!right) {
206 right = new RBTreeNode(data);
207 right->parent = this;
208 right->insert_case1();
209 }
210 else
211 right->insert(data);
212 }
213 else {
214 throw ValueExistsException();
215 }
216 CONSISTENCY_CHECK(this);
217 }
218
219 boost::optional<Data> find(const Data& data)
220 {
221 if (this->data == data) {
222 return this->data;
223 }
224 else if (data < this->data) {
225 if (left)
226 return left->find(data);
227 else
228 return boost::optional<Data>();
229 }
230 else {
231 if (right)
232 return right->find(data);
233 else
234 return boost::optional<Data>();
235 }
236 return boost::optional<Data>();
237 }
238
239 uint size() const
240 {
241 return 1 + (left ? left->size() : 0) + (right ? right->size() : 0);
242 }
243
244 uint depth() const
245 {
246 return 1 + std::max((left ? left->depth() : 0), (right ? right->depth() : 0));
247 }
248
249 uint total_depth(uint n) const
250 {
251 return n + (left ? left->total_depth(n + 1) : 0) + (right ? right->total_depth(n + 1) : 0);
252 }
253
254 bool consistent() const
255 {
256 bool retVal = true;
257 if (left)
258 retVal = retVal && (left->parent == this) && left->consistent();
259 if (right)
260 retVal = retVal && (right->parent == this) && right->consistent();
261 return retVal;
262 }
263
264 friend class RBTree;
265
266 };
267 RBTreeNode* node;
268 public:
269 RBTree() : node(0)
270 {
271 }
272
273 bool consistent() const
274 {
275 if (node == 0)
276 return true;
277 if (node->parent == 0 && node->consistent())
278 return true;
279 return false;
280 }
281
282 void insert(const Data& data)
283 {
284 if (node == 0) {
285 node = new RBTreeNode(data);
286 }
287 else {
288 node->insert(data);
289 }
290 node = node->getRootNode();
291 CONSISTENCY_CHECK(this);
292 }
293 boost::optional<Data> find(const Data& data)
294 {
295 if (node) {
296 return node->find(data);
297 }
298 else
299 return boost::optional<Data>();
300 }
301
302 uint size() const
303 {
304 if (!node)
305 return 0;
306 else
307 return node->size();
308 }
309
310 uint depth() const
311 {
312 if (!node)
313 return 0;
314 return node->depth();
315 }
316
317 float avg_depth() const
318 {
319 if (!node)
320 return 0;
321 return double(total_depth())/size();
322 }
323
324 uint total_depth() const
325 {
326 if (!node)
327 return 0;
328 return node->total_depth(1);
329 }
330
331 uint optimal_depth() const
332 {
333 int s = size();
334 if (s == 0)
335 return 0;
336 int d = s;
337 int targetlevel = 1;
338 while (d >>= 1)
339 ++targetlevel;
340 return targetlevel;
341 }
342 };
343
344 #endif //RBTREE_HPP