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;
140 #endif
141 }
142 
143 TQueue::~TQueue() {
144  if (root_ != NIL) {
145  deleteitem(root_);
146  }
147 }
148 
149 void TQueue::print() {
150  if (root_ != NIL) {
151  root_->t_iterate(prnt, 0);
152  }
153 }
154 
155 void TQueue::forall_callback(void (*f)(const TQItem*, int)) {
156  if (root_ != NIL) {
157  root_->t_iterate(f, 0);
158  }
159 }
160 
161 void TQueue::check(const char* mes) {
162 #if DOCHECK
163  errmess_ = mes;
164  if (root_ != NIL) {
165  root_->t_iterate(chk, 0);
166  }
167  errmess_ = nil;
168 #endif
169 }
170 
171 double TQueue::least_t() {
172  TQItem* b = least();
173  if (b) {
174  return b->t_;
175  } else {
176  return 1e15;
177  }
178 }
179 
181  STAT(nleast)
182 #if !FAST_LEAST || DOCHECK
183  TQItem* b;
184  b = root_;
185  if (b != NIL)
186  for (; b->left_ != NIL; b = b->left_) {
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 void TQueue::new_least() {
199  assert(least_ != NIL);
200  assert(least_->left_ == NIL);
201  TQItem* b = least_->right_;
202  if (b != NIL) {
203  for (; b->left_ != NIL; b = b->left_) {
204  ;
205  }
206  least_ = b;
207  } else {
208  b = least_->parent_;
209  if (b && b != NIL) {
210  assert(b->left_ == least_);
211  least_ = b;
212  } else {
213  least_ = NIL;
214  }
215  }
216 }
217 
218 void TQueue::move_least(double tnew) {
219  TQItem* b = least();
220  if (b) {
221  move(b, tnew);
222  }
223 }
224 
225 void TQueue::move(TQItem* i, double tnew) {
226  PSTART(1)
227  STAT(nmove)
228  // the long way
229  deleteNode(i);
230  insertNode(tnew, i);
231  PSTOP(1)
232 }
233 
234 void TQueue::statistics() {
235 #if COLLECT_TQueue_STATISTICS
236  Printf("insertions=%lu moves=%lu fastmoves=%lu removals=%lu calls to least=%lu\n",
237  ninsert,
238  nmove,
239  nfastmove,
240  nrem,
241  nleast);
242  Printf("calls to find=%lu balances=%lu complex removals=%lu\n", nfind, nbal, ncmplxrem);
243  Printf("comparisons=%lu leastsearch=%lu findsearch=%lu\n", ncompare, nleastsrch, nfindsrch);
244 #else
245  Printf("Turn on COLLECT_TQueue_STATISTICS_ in tqueue.h\n");
246 #endif
247 }
248 
249 void RBTQueue::rotateLeft(Node* x) {
250  /**************************
251  * rotate node x to left *
252  **************************/
253 
254  Node* y = x->right;
255 
256  /* establish x->right link */
257  x->right = y->left;
258  if (y->left != NIL)
259  y->left->parent = x;
260 
261  /* establish y->parent link */
262  if (y != NIL)
263  y->parent = x->parent;
264  if (x->parent) {
265  if (x == x->parent->left)
266  x->parent->left = y;
267  else
268  x->parent->right = y;
269  } else {
270  root = y;
271  }
272 
273  /* link x and y */
274  y->left = x;
275  if (x != NIL)
276  x->parent = y;
277 }
278 
279 void RBTQueue::rotateRight(Node* x) {
280  /****************************
281  * rotate node x to right *
282  ****************************/
283 
284  Node* y = x->left;
285 
286  /* establish x->left link */
287  x->left = y->right;
288  if (y->right != NIL)
289  y->right->parent = x;
290 
291  /* establish y->parent link */
292  if (y != NIL)
293  y->parent = x->parent;
294  if (x->parent) {
295  if (x == x->parent->right)
296  x->parent->right = y;
297  else
298  x->parent->left = y;
299  } else {
300  root = y;
301  }
302 
303  /* link x and y */
304  y->right = x;
305  if (x != NIL)
306  x->parent = y;
307 }
308 
309 void RBTQueue::insertFixup(Node* x) {
310  /*************************************
311  * maintain Red-Black tree balance *
312  * after inserting node x *
313  *************************************/
314 
315  /* check Red-Black properties */
316  while (x != root && x->parent->color == RED) {
317  /* we have a violation */
318  if (x->parent == x->parent->parent->left) {
319  Node* y = x->parent->parent->right;
320  if (y->color == RED) {
321  /* uncle is RED */
322  x->parent->color = BLACK;
323  y->color = BLACK;
324  x->parent->parent->color = RED;
325  x = x->parent->parent;
326  } else {
327  /* uncle is BLACK */
328  if (x == x->parent->right) {
329  /* make x a left child */
330  x = x->parent;
331  rotateLeft(x);
332  }
333 
334  /* recolor and rotate */
335  x->parent->color = BLACK;
336  x->parent->parent->color = RED;
337  rotateRight(x->parent->parent);
338  }
339  } else {
340  /* mirror image of above code */
341  Node* y = x->parent->parent->left;
342  if (y->color == RED) {
343  /* uncle is RED */
344  x->parent->color = BLACK;
345  y->color = BLACK;
346  x->parent->parent->color = RED;
347  x = x->parent->parent;
348  } else {
349  /* uncle is BLACK */
350  if (x == x->parent->left) {
351  x = x->parent;
352  rotateRight(x);
353  }
354  x->parent->color = BLACK;
355  x->parent->parent->color = RED;
356  rotateLeft(x->parent->parent);
357  }
358  }
359  }
360  root->color = BLACK;
361 }
362 
363 Node* RBTQueue::insert(double t, void* d) {
364  TQItem* i = tpool_->alloc();
365  i->data_ = d;
366  insertNode(t, i);
367  return i;
368 }
369 
370 void RBTQueue::insertNode(T data, Node* x) {
371  // printf("%p::insertNode %g\n", this, data);
372  Node *current, *parent;
373 
374 #if FAST_LEAST
375  STAT(ncompare)
376  if (data < least_t()) {
377  least_ = x;
378  }
379 #endif
380 
381  /***********************************************
382  * allocate node for data and insert in tree *
383  ***********************************************/
384 
385  /* find where node belongs */
386  STAT(ninsert)
387  current = root;
388  parent = 0;
389  while (current != NIL) {
390 #if 0
391  if (compEQ(data, current->data)) return (current);
392 #endif
393  parent = current;
394  current = compLT(data, current->data) ? current->left : current->right;
395  }
396 
397  /* setup new node */
398 #if 0
399  if ((x = malloc (sizeof(*x))) == 0) {
400  printf ("insufficient memory (insertNode)\n");
401  exit(1);
402  }
403 #endif
404  x->data = data;
405  x->parent = parent;
406  x->left = NIL;
407  x->right = NIL;
408  x->color = RED;
409 
410  /* insert node in tree */
411  if (parent) {
412  if (compLT(data, parent->data))
413  parent->left = x;
414  else
415  parent->right = x;
416  } else {
417  root = x;
418  }
419 
420  insertFixup(x);
421 }
422 
423 void RBTQueue::deleteFixup(Node* x) {
424  /*************************************
425  * maintain Red-Black tree balance *
426  * after deleting node x *
427  *************************************/
428 
429  while (x != root && x->color == BLACK) {
430  if (x == x->parent->left) {
431  Node* w = x->parent->right;
432  if (w->color == RED) {
433  w->color = BLACK;
434  x->parent->color = RED;
435  rotateLeft(x->parent);
436  w = x->parent->right;
437  }
438  if (w->left->color == BLACK && w->right->color == BLACK) {
439  w->color = RED;
440  x = x->parent;
441  } else {
442  if (w->right->color == BLACK) {
443  w->left->color = BLACK;
444  w->color = RED;
445  rotateRight(w);
446  w = x->parent->right;
447  }
448  w->color = x->parent->color;
449  x->parent->color = BLACK;
450  w->right->color = BLACK;
451  rotateLeft(x->parent);
452  x = root;
453  }
454  } else {
455  Node* w = x->parent->left;
456  if (w->color == RED) {
457  w->color = BLACK;
458  x->parent->color = RED;
459  rotateRight(x->parent);
460  w = x->parent->left;
461  }
462  if (w->right->color == BLACK && w->left->color == BLACK) {
463  w->color = RED;
464  x = x->parent;
465  } else {
466  if (w->left->color == BLACK) {
467  w->right->color = BLACK;
468  w->color = RED;
469  rotateLeft(w);
470  w = x->parent->left;
471  }
472  w->color = x->parent->color;
473  x->parent->color = BLACK;
474  w->left->color = BLACK;
475  rotateRight(x->parent);
476  x = root;
477  }
478  }
479  }
480  x->color = BLACK;
481 }
482 
483 void RBTQueue::remove(Node* z) {
484  if (z && z != NIL) {
485  deleteNode(z);
486  tpool_->free(z);
487  }
488 }
489 
490 void RBTQueue::deleteNode(Node* z) {
491  // printf("%p::deleteNode %g\n", this, z->t_);
492  Node *x, *y;
493 
494  STAT(nrem)
495  /*****************************
496  * delete node z from tree *
497  *****************************/
498 
499  if (z == NIL)
500  return;
501 
502 #if FAST_LEAST
503  if (least_ == z) {
504  new_least();
505  }
506 #endif
507 
508  if (z->left == NIL || z->right == NIL) {
509  /* y has a NIL node as a child */
510  y = z;
511  } else {
512  /* find tree successor with a NIL node as a child */
513  y = z->right;
514  while (y->left != NIL)
515  y = y->left;
516  }
517 
518  /* x is y's only child */
519  if (y->left != NIL)
520  x = y->left;
521  else
522  x = y->right;
523 
524  /* remove y from the parent chain */
525  x->parent = y->parent;
526  if (y->parent)
527  if (y == y->parent->left)
528  y->parent->left = x;
529  else
530  y->parent->right = x;
531  else
532  root = x;
533 
534 #if 0
535  // inadequate. does not preserve association between data and Node*
536  if (y != z) z->data = y->data;
537 #endif
538 
539  if (y->color == BLACK)
540  deleteFixup(x);
541 
542 #if 0
543  free (y);
544 #else
545  // we need to preserve the association between data and Node*
546  if (y != z) {
547  y->red_ = z->red_;
548  y->parent_ = z->parent_;
549  y->left_ = z->left_;
550  y->right_ = z->right_;
551  if (z->left_ != NIL) {
552  z->left_->parent_ = y;
553  }
554  if (z->right_ != NIL) {
555  z->right_->parent_ = y;
556  }
557  if (z->parent && z->parent_ != NIL) {
558  if (z->parent_->left_ == z) {
559  z->parent_->left_ = y;
560  } else {
561  z->parent_->right_ = y;
562  }
563  }
564  }
565 #endif
566 }
567 
569  STAT(nfind);
570  /*******************************
571  * find node containing data *
572  *******************************/
573 
574  Node* current = root;
575  while (current != NIL)
576  STAT(nfindsrch)
577  STAT(ncompare)
578  if (compEQ(data, current->data))
579  return (current);
580  else
581  current = compLT(data, current->data) ? current->left : current->right;
582  return (0);
583 }
#define nil
Definition: enter-scope.h:36
Definition: bbtqueue.h:6
virtual ~TQItem()
Definition: bbtqueue.cpp:9
double t_
Definition: bbtqueue.h:23
bool check()
Definition: bbtqueue.cpp:30
TQItem * right_
Definition: bbtqueue.h:25
TQItem()
Definition: bbtqueue.cpp:3
bool red_
Definition: rbtqueue.h:20
void t_iterate(void(*)(const TQItem *, int), int)
Definition: bbtqueue.cpp:78
TQItem * parent_
Definition: bbtqueue.h:26
TQItem * left_
Definition: bbtqueue.h:24
void * data_
Definition: bbtqueue.h:22
unsigned long nbal
Definition: bbtqueue.h:58
void deleteFixup(TQItem *)
void statistics()
Definition: bbtqueue.cpp:477
unsigned long nleastsrch
Definition: bbtqueue.h:59
double least_t()
Definition: bbtqueue.cpp:131
void deleteitem(TQItem *)
Definition: sptbinq.cpp:87
TQItem * least()
Definition: bbtqueue.cpp:140
TQItem * root_
Definition: bbtqueue.h:55
void check(const char *errmess)
Definition: bbtqueue.cpp:121
TQItemPool * tpool_
Definition: sptbinq.h:153
void insertNode(double t, TQItem *)
void rotateLeft(TQItem *)
void move(TQItem *, double tnew)
Definition: bbtqueue.cpp:185
unsigned long nmove
Definition: bbtqueue.h:59
TQItem * least_
Definition: bbtqueue.h:54
TQueue()
Definition: bbtqueue.cpp:90
unsigned long ninsert
Definition: bbtqueue.h:58
void print()
Definition: bbtqueue.cpp:109
unsigned long nrem
Definition: bbtqueue.h:58
void rotateRight(TQItem *)
unsigned long nfastmove
Definition: bbtqueue.h:59
void insertFixup(TQItem *)
unsigned long nfindsrch
Definition: bbtqueue.h:59
unsigned long ncompare
Definition: bbtqueue.h:59
void new_least()
Definition: bbtqueue.cpp:158
unsigned long nleast
Definition: bbtqueue.h:58
unsigned long nfind
Definition: bbtqueue.h:59
unsigned long ncmplxrem
Definition: bbtqueue.h:58
virtual ~TQueue()
Definition: bbtqueue.cpp:103
void forall_callback(void(*)(const TQItem *, int))
Definition: bbtqueue.cpp:115
void deleteNode(TQItem *)
void move_least(double tnew)
Definition: bbtqueue.cpp:178
double t
Definition: cvodeobj.cpp:59
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
#define assert(ex)
Definition: hocassrt.h:32
#define i
Definition: md1redef.h:12
#define STAT
Definition: model.h:117
#define Printf
Definition: model.h:237
#define printf
Definition: mwprefix.h:26
static List * current
Definition: nrnunit.cpp:12
static double remove(void *v)
Definition: ocdeck.cpp:207
#define PSTOP(i)
Definition: profile.h:11
#define PSTART(i)
Definition: profile.h:10
static void deleteitem(TQItem *i)
Definition: rbtqueue.cpp:78
static TQItem * sentinel
Definition: rbtqueue.cpp:65
#define NIL
Definition: rbtqueue.cpp:64
#define left
Definition: rbtqueue.cpp:45
#define data
Definition: rbtqueue.cpp:49
static void prnt(const TQItem *b, int level)
Definition: rbtqueue.cpp:97
double T
Definition: rbtqueue.cpp:25
#define compLT(a, b)
Definition: rbtqueue.cpp:28
#define compEQ(a, b)
Definition: rbtqueue.cpp:29
static void chk(TQItem *b, int level)
Definition: rbtqueue.cpp:106
#define Node
Definition: rbtqueue.cpp:48
#define BLACK
Definition: rbtqueue.cpp:51
#define RED
Definition: rbtqueue.cpp:52
#define parent
Definition: rbtqueue.cpp:47
#define root
Definition: rbtqueue.cpp:53
#define color
Definition: rbtqueue.cpp:50
#define right
Definition: rbtqueue.cpp:46
int find(const int, const int, const int, const int, const int)
Definition: section.h:133
static const char * errmess_
Definition: tqueue.cpp:20
static double insert(void *v)
Definition: tqueue.cpp:22