NEURON
rbtqueue.cpp
Go to the documentation of this file.
1 // red black tree
2 /* Derived from
3 http://ciips.ee.uwa.edu.au/~morris/Year2/PLDS210/niemann/s_man.htm
4 Sorting and Searching Algorithms:
5 A Cookbook
6 by
7 Thomas Niemann
8 */
9 /* The original c code is enclosed in #if 0 and the original functions
10 are given the class name RBTQueue (which is defined as TQueue)
11 whereas my own analogous class methods to the old TQueue have the same name
12 */
13 
14 /* red-black tree */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <stdarg.h>
20 
21 
22 #if 0
23 typedef int T; /* type of item to be stored */
24 #else
25 typedef double T;
26 #endif
27 
28 #define compLT(a,b) (a < b)
29 #define compEQ(a,b) (a == b)
30 
31 #if 0
32 /* Red-Black tree description */
33 typedef enum { BLACK, RED } nodeColor;
34 #endif
35 
36 #if 0
37 typedef struct Node_ {
38  struct Node_ *left; /* left child */
39  struct Node_ *right; /* right child */
40  struct Node_ *parent; /* parent */
41  nodeColor color; /* node color (BLACK, RED) */
42  T data; /* data stored in node */
43 } Node;
44 #else
45 #define left left_
46 #define right right_
47 #define parent parent_
48 #define Node TQItem
49 #define data t_
50 #define color red_
51 #define BLACK false
52 #define RED true
53 #define root root_
54 #endif
55 
56 #if 0
57 #define NIL &sentinel /* all leafs are sentinels */
58 Node sentinel = { NIL, NIL, 0, BLACK, 0};
59 Node *root = NIL; /* root of Red-Black tree */
60 
61 #else
62 
63 #undef NIL
64 #define NIL sentinel
65 static TQItem* sentinel;
66 #endif
67 
69  left_ = NIL;
70  right_ = NIL;
71  parent_ = nil;
72 }
73 
75  assert(this != NIL);
76 }
77 
78 static void deleteitem(TQItem* i) {
79  assert(i != NIL);
80  if (i->left_ && i->left != NIL) {
81  deleteitem(i->left_);
82  }
83  if (i->right_ && i->right != NIL) {
84  deleteitem(i->right_);
85  }
86  i->left_ = nil;
87  i->right_ = nil;
88  tpool_->free(i);
89 }
90 
91 bool TQItem::check() {
92 #if DOCHECK
93 #endif
94  return true;
95 }
96 
97 static void prnt(const TQItem* b, int level) {
98  int i;
99  for (i=0; i < level; ++i) {
100  Printf(" ");
101  }
102 // printf("%g %c %d\n", b->t_, b->data_?'x':'o', b->red_);
103  Printf("%g %c %d Q=%p D=%p\n", b->t_, b->data_?'x':'o', b->red_, b, b->data_);
104 }
105 
106 static void chk(TQItem* b, int level) {
107  if (!b->check()) {
108  hoc_execerror("chk failed", errmess_);
109  }
110 }
111 
112 void TQItem::t_iterate(void (*f)(const TQItem*, int), int level) {
113  if (left_ && left_ != NIL) {
114  left_->t_iterate(f, level+1);
115  }
116  f(this, level);
117  if (right_ && right_ != NIL) {
118  right_->t_iterate(f, level+1);
119  }
120 }
121 
122 TQueue::TQueue() {
123  if (!sentinel) {
124  sentinel = new TQItem();
125  sentinel->red_ = BLACK;
126  sentinel->t_ = 0.;
127  sentinel->data_ = nil;
128  sentinel->left_ = NIL;
129  sentinel->right_ = NIL;
130  }
131  if (!tpool_) {
132  tpool_ = new TQItemPool(1000);
133  }
134  root_ = NIL;
135  least_ = NIL;
136 
137 #if COLLECT_TQueue_STATISTICS
138  nmove = ninsert = nrem = nleast = nbal = ncmplxrem = 0;
139  nfastmove = ncompare = nleastsrch = nfind = nfindsrch = 0;
140 #endif
141 }
142 
143 TQueue::~TQueue() {
144  if (root_ != NIL) {
145  deleteitem(root_);
146 
147  }
148 }
149 
150 void TQueue::print() {
151  if (root_!= NIL) {
152  root_->t_iterate(prnt, 0);
153  }
154 }
155 
156 void TQueue::forall_callback(void(*f)(const TQItem*, int)) {
157  if (root_ != NIL ) {
158  root_->t_iterate(f, 0);
159  }
160 }
161 
162 void TQueue::check(const char* mes) {
163 #if DOCHECK
164  errmess_ = mes;
165  if (root_ != NIL) {
166  root_->t_iterate(chk, 0);
167  }
168  errmess_ = nil;
169 #endif
170 }
171 
172 double TQueue::least_t() {
173  TQItem* b = least();
174  if (b) {
175  return b->t_;
176  }else{
177  return 1e15;
178  }
179 }
180 
182  STAT(nleast)
183 #if !FAST_LEAST || DOCHECK
184  TQItem* b;
185  b = root_;
186  if (b != NIL) for (; b->left_ != NIL; b = b->left_) {
187  STAT(nleastsrch)
188  }
189 #if DOCHECK
190  assert(least_ == b);
191 #else
192  least_ = b;
193 #endif
194 #endif
195  return least_ != NIL ? least_ : nil ;
196 
197 }
198 
199 void TQueue::new_least() {
200  assert(least_ != NIL);
201  assert(least_->left_ == NIL);
202  TQItem* b = least_->right_;
203  if (b != NIL) {
204  for (;b->left_ != NIL; b = b->left_) {;}
205  least_ = b;
206  }else{
207  b = least_->parent_;
208  if (b && b != NIL) {
209  assert(b->left_ == least_);
210  least_ = b;
211  }else{
212  least_ = NIL;
213  }
214  }
215 }
216 
217 void TQueue::move_least(double tnew) {
218  TQItem* b = least();
219  if (b) {
220  move(b, tnew);
221  }
222 }
223 
224 void TQueue::move(TQItem* i, double tnew) {
225 PSTART(1)
226  STAT(nmove)
227  // the long way
228  deleteNode(i);
229  insertNode(tnew, i);
230 PSTOP(1)
231 }
232 
233 void TQueue::statistics() {
234 #if COLLECT_TQueue_STATISTICS
235  Printf("insertions=%lu moves=%lu fastmoves=%lu removals=%lu calls to least=%lu\n", ninsert, nmove, nfastmove, nrem, nleast);
236  Printf("calls to find=%lu balances=%lu complex removals=%lu\n", nfind, nbal, ncmplxrem);
237  Printf("comparisons=%lu leastsearch=%lu findsearch=%lu\n", ncompare, nleastsrch, nfindsrch);
238 #else
239  Printf("Turn on COLLECT_TQueue_STATISTICS_ in tqueue.h\n");
240 #endif
241 }
242 
243 void RBTQueue::rotateLeft(Node *x) {
244 
245  /**************************
246  * rotate node x to left *
247  **************************/
248 
249  Node *y = x->right;
250 
251  /* establish x->right link */
252  x->right = y->left;
253  if (y->left != NIL) y->left->parent = x;
254 
255  /* establish y->parent link */
256  if (y != NIL) y->parent = x->parent;
257  if (x->parent) {
258  if (x == x->parent->left)
259  x->parent->left = y;
260  else
261  x->parent->right = y;
262  } else {
263  root = y;
264  }
265 
266  /* link x and y */
267  y->left = x;
268  if (x != NIL) x->parent = y;
269 }
270 
271 void RBTQueue::rotateRight(Node *x) {
272 
273  /****************************
274  * rotate node x to right *
275  ****************************/
276 
277  Node *y = x->left;
278 
279  /* establish x->left link */
280  x->left = y->right;
281  if (y->right != NIL) y->right->parent = x;
282 
283  /* establish y->parent link */
284  if (y != NIL) y->parent = x->parent;
285  if (x->parent) {
286  if (x == x->parent->right)
287  x->parent->right = y;
288  else
289  x->parent->left = y;
290  } else {
291  root = y;
292  }
293 
294  /* link x and y */
295  y->right = x;
296  if (x != NIL) x->parent = y;
297 }
298 
299 void RBTQueue::insertFixup(Node *x) {
300 
301  /*************************************
302  * maintain Red-Black tree balance *
303  * after inserting node x *
304  *************************************/
305 
306  /* check Red-Black properties */
307  while (x != root && x->parent->color == RED) {
308  /* we have a violation */
309  if (x->parent == x->parent->parent->left) {
310  Node *y = x->parent->parent->right;
311  if (y->color == RED) {
312 
313  /* uncle is RED */
314  x->parent->color = BLACK;
315  y->color = BLACK;
316  x->parent->parent->color = RED;
317  x = x->parent->parent;
318  } else {
319 
320  /* uncle is BLACK */
321  if (x == x->parent->right) {
322  /* make x a left child */
323  x = x->parent;
324  rotateLeft(x);
325  }
326 
327  /* recolor and rotate */
328  x->parent->color = BLACK;
329  x->parent->parent->color = RED;
330  rotateRight(x->parent->parent);
331  }
332  } else {
333 
334  /* mirror image of above code */
335  Node *y = x->parent->parent->left;
336  if (y->color == RED) {
337 
338  /* uncle is RED */
339  x->parent->color = BLACK;
340  y->color = BLACK;
341  x->parent->parent->color = RED;
342  x = x->parent->parent;
343  } else {
344 
345  /* uncle is BLACK */
346  if (x == x->parent->left) {
347  x = x->parent;
348  rotateRight(x);
349  }
350  x->parent->color = BLACK;
351  x->parent->parent->color = RED;
352  rotateLeft(x->parent->parent);
353  }
354  }
355  }
356  root->color = BLACK;
357 }
358 
359 Node* RBTQueue::insert(double t, void* d) {
360  TQItem* i = tpool_->alloc();
361  i->data_ = d;
362  insertNode(t, i);
363  return i;
364 }
365 
366 void RBTQueue::insertNode(T data, Node* x) {
367 //printf("%p::insertNode %g\n", this, data);
368  Node *current, *parent;
369 
370 #if FAST_LEAST
371  STAT(ncompare)
372  if (data < least_t()) {
373  least_ = x;
374  }
375 #endif
376 
377  /***********************************************
378  * allocate node for data and insert in tree *
379  ***********************************************/
380 
381  /* find where node belongs */
382  STAT(ninsert)
383  current = root;
384  parent = 0;
385  while (current != NIL) {
386 #if 0
387  if (compEQ(data, current->data)) return (current);
388 #endif
389  parent = current;
390  current = compLT(data, current->data) ?
391  current->left : current->right;
392  }
393 
394  /* setup new node */
395 #if 0
396  if ((x = malloc (sizeof(*x))) == 0) {
397  printf ("insufficient memory (insertNode)\n");
398  exit(1);
399  }
400 #endif
401  x->data = data;
402  x->parent = parent;
403  x->left = NIL;
404  x->right = NIL;
405  x->color = RED;
406 
407  /* insert node in tree */
408  if(parent) {
409  if(compLT(data, parent->data))
410  parent->left = x;
411  else
412  parent->right = x;
413  } else {
414  root = x;
415  }
416 
417  insertFixup(x);
418 }
419 
420 void RBTQueue::deleteFixup(Node *x) {
421 
422  /*************************************
423  * maintain Red-Black tree balance *
424  * after deleting node x *
425  *************************************/
426 
427  while (x != root && x->color == BLACK) {
428  if (x == x->parent->left) {
429  Node *w = x->parent->right;
430  if (w->color == RED) {
431  w->color = BLACK;
432  x->parent->color = RED;
433  rotateLeft (x->parent);
434  w = x->parent->right;
435  }
436  if (w->left->color == BLACK && w->right->color == BLACK) {
437  w->color = RED;
438  x = x->parent;
439  } else {
440  if (w->right->color == BLACK) {
441  w->left->color = BLACK;
442  w->color = RED;
443  rotateRight (w);
444  w = x->parent->right;
445  }
446  w->color = x->parent->color;
447  x->parent->color = BLACK;
448  w->right->color = BLACK;
449  rotateLeft (x->parent);
450  x = root;
451  }
452  } else {
453  Node *w = x->parent->left;
454  if (w->color == RED) {
455  w->color = BLACK;
456  x->parent->color = RED;
457  rotateRight (x->parent);
458  w = x->parent->left;
459  }
460  if (w->right->color == BLACK && w->left->color == BLACK) {
461  w->color = RED;
462  x = x->parent;
463  } else {
464  if (w->left->color == BLACK) {
465  w->right->color = BLACK;
466  w->color = RED;
467  rotateLeft (w);
468  w = x->parent->left;
469  }
470  w->color = x->parent->color;
471  x->parent->color = BLACK;
472  w->left->color = BLACK;
473  rotateRight (x->parent);
474  x = root;
475  }
476  }
477  }
478  x->color = BLACK;
479 }
480 
481 void RBTQueue::remove(Node* z) {
482  if (z && z != NIL) {
483  deleteNode(z);
484  tpool_->free(z);
485  }
486 }
487 
488 void RBTQueue::deleteNode(Node *z) {
489 //printf("%p::deleteNode %g\n", this, z->t_);
490  Node *x, *y;
491 
492  STAT(nrem)
493  /*****************************
494  * delete node z from tree *
495  *****************************/
496 
497  if (z == NIL) return;
498 
499 #if FAST_LEAST
500  if (least_ == z) {
501  new_least();
502  }
503 #endif
504 
505  if (z->left == NIL || z->right == NIL) {
506  /* y has a NIL node as a child */
507  y = z;
508  } else {
509  /* find tree successor with a NIL node as a child */
510  y = z->right;
511  while (y->left != NIL) y = y->left;
512  }
513 
514  /* x is y's only child */
515  if (y->left != NIL)
516  x = y->left;
517  else
518  x = y->right;
519 
520  /* remove y from the parent chain */
521  x->parent = y->parent;
522  if (y->parent)
523  if (y == y->parent->left)
524  y->parent->left = x;
525  else
526  y->parent->right = x;
527  else
528  root = x;
529 
530 #if 0
531  // inadequate. does not preserve association between data and Node*
532  if (y != z) z->data = y->data;
533 #endif
534 
535  if (y->color == BLACK)
536  deleteFixup (x);
537 
538 #if 0
539  free (y);
540 #else
541  //we need to preserve the association between data and Node*
542  if (y != z) {
543  y->red_ = z->red_;
544  y->parent_ = z->parent_;
545  y->left_ = z->left_;
546  y->right_ = z->right_;
547  if (z->left_ != NIL) { z->left_->parent_ = y; }
548  if (z->right_ != NIL) { z->right_->parent_ = y; }
549  if (z->parent && z->parent_ != NIL) {
550  if (z->parent_->left_ == z) {
551  z->parent_->left_ = y;
552  }else{
553  z->parent_->right_ = y;
554  }
555  }
556  }
557 #endif
558 }
559 
561 
562  STAT(nfind);
563  /*******************************
564  * find node containing data *
565  *******************************/
566 
567  Node *current = root;
568  while(current != NIL)
569  STAT(nfindsrch)
570  STAT(ncompare)
571  if(compEQ(data, current->data))
572  return (current);
573  else
574  current = compLT (data, current->data) ?
575  current->left : current->right;
576  return(0);
577 }
static void chk(TQItem *b, int level)
Definition: rbtqueue.cpp:106
#define data
Definition: rbtqueue.cpp:49
static TQItem * sentinel
Definition: rbtqueue.cpp:65
#define Printf
Definition: model.h:252
static void deleteitem(TQItem *i)
Definition: rbtqueue.cpp:78
#define PSTART(i)
Definition: profile.h:10
static void prnt(const TQItem *b, int level)
Definition: rbtqueue.cpp:97
#define assert(ex)
Definition: hocassrt.h:26
double T
Definition: rbtqueue.cpp:25
void print()
Definition: bbtqueue.cpp:114
TQItem()
Definition: bbtqueue.cpp:3
bool red_
Definition: rbtqueue.h:19
double t_
Definition: bbtqueue.h:18
#define RED
Definition: rbtqueue.cpp:52
Definition: bbtqueue.h:6
bool check()
Definition: bbtqueue.cpp:30
void statistics()
Definition: bbtqueue.cpp:474
void forall_callback(void(*)(const TQItem *, int))
Definition: bbtqueue.cpp:120
double least_t()
Definition: bbtqueue.cpp:136
void new_least()
Definition: bbtqueue.cpp:163
#define BLACK
Definition: rbtqueue.cpp:51
TQItem * least()
Definition: bbtqueue.cpp:145
virtual ~TQItem()
Definition: bbtqueue.cpp:9
#define color
Definition: rbtqueue.cpp:50
#define root
Definition: rbtqueue.cpp:53
#define printf
Definition: mwprefix.h:26
static double remove(void *v)
Definition: ocdeck.cpp:206
static double insert(void *v)
Definition: tqueue.cpp:22
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
#define compLT(a, b)
Definition: rbtqueue.cpp:28
#define nil
Definition: enter-scope.h:36
#define parent
Definition: rbtqueue.cpp:47
#define left
Definition: rbtqueue.cpp:45
#define compEQ(a, b)
Definition: rbtqueue.cpp:29
virtual void move(const Event &e)
Definition: ocinput.h:19
TQItem * left_
Definition: bbtqueue.h:19
#define right
Definition: rbtqueue.cpp:46
static List * current
Definition: nrnunit.cpp:12
void move_least(double tnew)
Definition: bbtqueue.cpp:181
static const char * errmess_
Definition: tqueue.cpp:20
#define PSTOP(i)
Definition: profile.h:11
#define Node
Definition: rbtqueue.cpp:48
TQItem * parent_
Definition: bbtqueue.h:21
virtual ~TQueue()
Definition: bbtqueue.cpp:107
#define i
Definition: md1redef.h:12
#define STAT
Definition: model.h:117
static double least(void *v)
Definition: tqueue.cpp:33
int find(const int, const int, const int, const int, const int)
#define NIL
Definition: rbtqueue.cpp:64
void * data_
Definition: bbtqueue.h:17
void check(const char *errmess)
Definition: bbtqueue.cpp:126
double t
Definition: init.cpp:123
Definition: section.h:132
TQueue()
Definition: bbtqueue.cpp:94
void move(TQItem *, double tnew)
Definition: bbtqueue.cpp:188
TQItem * right_
Definition: bbtqueue.h:20
void t_iterate(void(*)(const TQItem *, int), int)
Definition: bbtqueue.cpp:82