NEURON
sptree.hpp
Go to the documentation of this file.
1 /*
2 ** sptree.hpp: The following type declarations provide the binary tree
3 ** representation of event-sets or priority queues needed by splay trees
4 **
5 ** assumes that data and datb will be provided by the application
6 ** to hold all application specific information
7 **
8 ** assumes that key will be provided by the application, comparable
9 ** with the compare function applied to the addresses of two keys.
10 **
11 ** Originaly written by Douglas W. Jones in Fortran helped by Srinivas R. Sataluri.
12 ** Translated by David Brower to C circa 1988.
13 ** Some fixes by Mark Moraes <moraes@csri.toronto.edu>.
14 **
15 ** For some litterature about this Splay tree: https://en.wikipedia.org/wiki/Splay_tree
16 ** The original implementation is based on:
17 ** Self Adjusting Binary Trees
18 ** by D. D. Sleator and R. E. Tarjan,
19 ** Proc. ACM SIGACT Symposium on Theory
20 ** of Computing (Boston, Apr 1983) 235-245.
21 **
22 ** For more insights, `enqueue` is doing the splay top-down.
23 ** `splay` itself is doing it bottom-up.
24 */
25 
26 #pragma once
27 
28 #include <functional>
29 
30 template <typename T>
31 class SPTree {
32  public:
33  SPTree() = default;
34 
35  // Is this SPTree empty?
36  bool empty() const;
37 
38  // Return the value of enqcmps.
39  int get_enqcmps() const;
40 
41  // Insert item in the tree.
42  //
43  // Put `n` after all other nodes with the same key; when this is
44  // done, `n` will be the root of the splay tree, all nodes
45  // with keys less than or equal to that of `n` will be in the
46  // left subtree, all with greater keys will be in the right subtree;
47  // the tree is split into these subtrees from the top down, with rotations
48  // performed along the way to shorten the left branch of the right subtree
49  // and the right branch of the left subtree
50  void enqueue(T* n);
51 
52  // Return and remove the first node.
53  //
54  // Remove and return the first node; this deletes
55  // (and returns) the leftmost node, replacing it with its right
56  // subtree (if there is one); on the way to the leftmost node, rotations
57  // are performed to shorten the left branch of the tree.
58  T* dequeue();
59 
60  // Return the element in the tree with the lowest key.
61  //
62  // Returns a pointer to the item with the lowest key.
63  // The left branch will be shortened as if the tree had been splayed around the first item.
64  // This is done by dequeue and enqueuing the first item.
65  T* first();
66 
67  // Remove node `n` from the tree.
68  //
69  // `n` is removed; the resulting splay tree has been splayed
70  // around its new root, which is the successor of n
71  void remove(T* n);
72 
73  // Find a node with the given key.
74  //
75  // Splays the found node to the root.
76  T* find(double key);
77 
78  // Apply the function `f` to each node in ascending order.
79  //
80  // `f` is the function that will be applied to nodes. The first argument will be
81  // a pointer to the current node, the integer value is unused and will always be `0`.
82  // If n is given, start at that node, otherwise start from the head.
83  void apply_all(void (*f)(const T*, int), T* n) const;
84 
85  private:
86  // Dequeue the first node in the subtree np
87  T* dequeue(T** np);
88 
89  // Reorganize the tree.
90  //
91  // The tree is reorganized so that `n` is the root of the
92  // splay tree; operation is undefined if `n` is not
93  // in the tree; the tree is split from `n` up to the old root, with all
94  // nodes to the left of `n` ending up in the left subtree, and all nodes
95  // to the right of n ending up in the right subtree; the left branch of
96  // the right subtree and the right branch of the left subtree are
97  // shortened in the process
98  //
99  // This code assumes that `n` is not `nullptr` and is in the tree; it can sometimes
100  // detect that `n` is not in the tree and throw an exception.
101  void splay(T* n);
102 
103  // Return the first element in the tree witout splaying.
104  //
105  // Returns a reference to the head event.
106  // Avoids splaying but just searches for and returns a pointer to
107  // the bottom of the left branch.
108  T* fast_first() const;
109 
110  // Fast return next higher item in the tree, or nullptr
111  //
112  // Return the successor of `n`, represented as a splay tree.
113  // This is a fast (on average) version that does not splay.
114  T* fast_next(T* n) const;
115 
116  // The node at the top of the tree
117  T* root{};
118 
119  // Number of comparison in enqueue
120  int enqcmps{};
121 };
122 
123 template <typename T>
124 bool SPTree<T>::empty() const {
125  return root == nullptr;
126 }
127 
128 template <typename T>
130  return enqcmps;
131 }
132 
133 template <typename T>
135  T* left; /* the rightmost node in the left tree */
136  T* right; /* the leftmost node in the right tree */
137  T* next; /* the root of the unsplit part */
138  T* temp;
139 
140  double key;
141 
142  n->uplink = nullptr;
143  next = root;
144  root = n;
145  if (next == nullptr) /* trivial enq */
146  {
147  n->leftlink = nullptr;
148  n->rightlink = nullptr;
149  } else /* difficult enq */
150  {
151  key = n->key;
152  left = n;
153  right = n;
154 
155  /* n's left and right children will hold the right and left
156  splayed trees resulting from splitting on n->key;
157  note that the children will be reversed! */
158 
159  enqcmps++;
160  if (next->key - key > 0) {
161  goto two;
162  }
163 
164  one: /* assert next->key <= key */
165  do /* walk to the right in the left tree */
166  {
167  temp = next->rightlink;
168  if (temp == nullptr) {
169  left->rightlink = next;
170  next->uplink = left;
171  right->leftlink = nullptr;
172  goto done; /* job done, entire tree split */
173  }
174 
175  enqcmps++;
176  if (temp->key - key > 0) {
177  left->rightlink = next;
178  next->uplink = left;
179  left = next;
180  next = temp;
181  goto two; /* change sides */
182  }
183 
184  next->rightlink = temp->leftlink;
185  if (temp->leftlink != nullptr) {
186  temp->leftlink->uplink = next;
187  }
188  left->rightlink = temp;
189  temp->uplink = left;
190  temp->leftlink = next;
191  next->uplink = temp;
192  left = temp;
193  next = temp->rightlink;
194  if (next == nullptr) {
195  right->leftlink = nullptr;
196  goto done; /* job done, entire tree split */
197  }
198 
199  enqcmps++;
200 
201  } while (next->key - key <= 0); /* change sides */
202 
203  two: /* assert next->key > key */
204  do /* walk to the left in the right tree */
205  {
206  temp = next->leftlink;
207  if (temp == nullptr) {
208  right->leftlink = next;
209  next->uplink = right;
210  left->rightlink = nullptr;
211  goto done; /* job done, entire tree split */
212  }
213 
214  enqcmps++;
215  if (temp->key - key <= 0) {
216  right->leftlink = next;
217  next->uplink = right;
218  right = next;
219  next = temp;
220  goto one; /* change sides */
221  }
222  next->leftlink = temp->rightlink;
223  if (temp->rightlink != nullptr) {
224  temp->rightlink->uplink = next;
225  }
226  right->leftlink = temp;
227  temp->uplink = right;
228  temp->rightlink = next;
229  next->uplink = temp;
230  right = temp;
231  next = temp->leftlink;
232  if (next == nullptr) {
233  left->rightlink = nullptr;
234  goto done; /* job done, entire tree split */
235  }
236 
237  enqcmps++;
238 
239  } while (next->key - key > 0); /* change sides */
240 
241  goto one;
242 
243  done: /* split is done, branches of `n` need reversal */
244  temp = n->leftlink;
245  n->leftlink = n->rightlink;
246  n->rightlink = temp;
247  }
248 }
249 
250 template <typename T>
252  return dequeue(&root);
253 }
254 
255 template <typename T>
256 T* SPTree<T>::dequeue(T** np) /* pointer to a node pointer */
257 {
258  T* deq; /* one to return */
259  T* next; /* the next thing to deal with */
260  T* left; /* the left child of next */
261  T* farleft; /* the left child of left */
262  T* farfarleft; /* the left child of farleft */
263 
264  if (np == nullptr || *np == nullptr) {
265  deq = nullptr;
266  } else {
267  next = *np;
268  left = next->leftlink;
269  if (left == nullptr) {
270  deq = next;
271  *np = next->rightlink;
272 
273  if (*np != nullptr) {
274  (*np)->uplink = nullptr;
275  }
276  } else {
277  for (;;) /* left is not null */
278  {
279  /* next is not it, left is not nullptr, might be it */
280  farleft = left->leftlink;
281  if (farleft == nullptr) {
282  deq = left;
283  next->leftlink = left->rightlink;
284  if (left->rightlink != nullptr)
285  left->rightlink->uplink = next;
286  break;
287  }
288 
289  /* next, left are not it, farleft is not nullptr, might be it */
290  farfarleft = farleft->leftlink;
291  if (farfarleft == nullptr) {
292  deq = farleft;
293  left->leftlink = farleft->rightlink;
294  if (farleft->rightlink != nullptr)
295  farleft->rightlink->uplink = left;
296  break;
297  }
298 
299  /* next, left, farleft are not it, rotate */
300  next->leftlink = farleft;
301  farleft->uplink = next;
302  left->leftlink = farleft->rightlink;
303  if (farleft->rightlink != nullptr)
304  farleft->rightlink->uplink = left;
305  farleft->rightlink = left;
306  left->uplink = farleft;
307  next = farleft;
308  left = farfarleft;
309  }
310  }
311  }
312 
313  return deq;
314 }
315 
316 template <typename T>
317 void SPTree<T>::splay(T* n) {
318  T* up; /* points to the node being dealt with */
319  T* prev; /* a descendent of up, already dealt with */
320  T* upup; /* the parent of up */
321  T* upupup; /* the grandparent of up */
322  T* left; /* the top of left subtree being built */
323  T* right; /* the top of right subtree being built */
324 
325 
326  left = n->leftlink;
327  right = n->rightlink;
328  prev = n;
329  up = prev->uplink;
330 
331  while (up != nullptr) {
332  /* walk up the tree towards the root, splaying all to the left of
333  `n` into the left subtree, all to right into the right subtree */
334  upup = up->uplink;
335  if (up->leftlink == prev) /* up is to the right of n */
336  {
337  if (upup != nullptr && upup->leftlink == up) /* rotate */
338  {
339  upupup = upup->uplink;
340  upup->leftlink = up->rightlink;
341  if (upup->leftlink != nullptr) {
342  upup->leftlink->uplink = upup;
343  }
344  up->rightlink = upup;
345  upup->uplink = up;
346  if (upupup == nullptr) {
347  root = up;
348  } else if (upupup->leftlink == upup) {
349  upupup->leftlink = up;
350  } else {
351  upupup->rightlink = up;
352  }
353  up->uplink = upupup;
354  upup = upupup;
355  }
356  up->leftlink = right;
357  if (right != nullptr) {
358  right->uplink = up;
359  }
360  right = up;
361 
362  } else /* up is to the left of `n` */
363  {
364  if (upup != nullptr && upup->rightlink == up) /* rotate */
365  {
366  upupup = upup->uplink;
367  upup->rightlink = up->leftlink;
368  if (upup->rightlink != nullptr) {
369  upup->rightlink->uplink = upup;
370  }
371  up->leftlink = upup;
372  upup->uplink = up;
373  if (upupup == nullptr) {
374  root = up;
375  } else if (upupup->rightlink == upup) {
376  upupup->rightlink = up;
377  } else {
378  upupup->leftlink = up;
379  }
380  up->uplink = upupup;
381  upup = upupup;
382  }
383  up->rightlink = left;
384  if (left != nullptr) {
385  left->uplink = up;
386  }
387  left = up;
388  }
389  prev = up;
390  up = upup;
391  }
392 
393 #ifdef DEBUG
394  if (root != prev) {
395  /*fprintf(stderr, " *** bug in splay: n not in q *** " ); */
396  abort();
397  }
398 #endif
399 
400  n->leftlink = left;
401  n->rightlink = right;
402  if (left != nullptr) {
403  left->uplink = n;
404  }
405  if (right != nullptr) {
406  right->uplink = n;
407  }
408  root = n;
409  n->uplink = nullptr;
410 }
411 
412 template <typename T>
414  if (empty()) {
415  return nullptr;
416  }
417 
418  T* x = dequeue();
419  x->rightlink = root;
420  x->leftlink = nullptr;
421  x->uplink = nullptr;
422  if (root != nullptr) {
423  root->uplink = x;
424  }
425  root = x;
426 
427  return x;
428 }
429 
430 template <typename T>
432  splay(n);
433  T* x = dequeue(&root->rightlink);
434  if (x == nullptr) /* empty right subtree */
435  {
436  root = root->leftlink;
437  if (root) {
438  root->uplink = nullptr;
439  }
440  } else /* non-empty right subtree */
441  {
442  x->uplink = nullptr;
443  x->leftlink = root->leftlink;
444  x->rightlink = root->rightlink;
445  if (x->leftlink != nullptr) {
446  x->leftlink->uplink = x;
447  }
448  if (x->rightlink != nullptr) {
449  x->rightlink->uplink = x;
450  }
451  root = x;
452  }
453 }
454 
455 template <typename T>
456 T* SPTree<T>::find(double key) {
457  T* n = root;
458  while (n && key != n->key) {
459  n = key < n->key ? n->leftlink : n->rightlink;
460  }
461 
462  /* reorganize tree around this node */
463  if (n != nullptr) {
464  splay(n);
465  }
466 
467  return n;
468 }
469 
470 template <typename T>
471 void SPTree<T>::apply_all(void (*f)(const T*, int), T* n) const {
472  for (T* x = n != nullptr ? n : fast_first(); x != nullptr; x = fast_next(x)) {
473  std::invoke(f, x, 0);
474  }
475 }
476 
477 template <typename T>
479  if (empty()) {
480  return nullptr;
481  }
482 
483  T* x = root;
484  while (x->leftlink != nullptr) {
485  x = x->leftlink;
486  }
487  return x;
488 }
489 
490 template <typename T>
491 T* SPTree<T>::fast_next(T* n) const {
492  if (n == nullptr) {
493  return n;
494  }
495 
496  // If there is a right element, the next element is the smallest item on the most left of this
497  // right element
498  if (T* x = n->rightlink; x != nullptr) {
499  while (x->leftlink != nullptr) {
500  x = x->leftlink;
501  }
502  return x;
503  }
504 
505  // Otherwise we have to go up and left
506  T* next = nullptr;
507  T* x = n->uplink;
508  while (x != nullptr) {
509  if (x->leftlink == n) {
510  next = x;
511  x = nullptr;
512  } else {
513  n = x;
514  x = n->uplink;
515  }
516  }
517 
518  return next;
519 }
void apply_all(void(*f)(const T *, int), T *n) const
Definition: sptree.hpp:471
T * find(double key)
Definition: sptree.hpp:456
T * fast_next(T *n) const
Definition: sptree.hpp:491
T * root
Definition: sptree.hpp:117
bool empty() const
Definition: sptree.hpp:124
int enqcmps
Definition: sptree.hpp:120
void remove(T *n)
Definition: sptree.hpp:431
T * first()
Definition: sptree.hpp:413
void splay(T *n)
Definition: sptree.hpp:317
void enqueue(T *n)
Definition: sptree.hpp:134
T * fast_first() const
Definition: sptree.hpp:478
T * dequeue()
Definition: sptree.hpp:251
SPTree()=default
int get_enqcmps() const
Definition: sptree.hpp:129
T * dequeue(T **np)
Definition: sptree.hpp:256
#define splay
Definition: tqueue.hpp:57
#define key
Definition: tqueue.hpp:45
Item * prev(Item *item)
Definition: list.cpp:94
Item * next(Item *item)
Definition: list.cpp:89
static int np
Definition: mpispike.cpp:25
int root
Definition: cellorder.cpp:622
int const size_t const size_t n
Definition: nrngsl.h:10
static double done(void *v)
Definition: ocbbs.cpp:251