Lumiera  0.pre.03
»edit your freedom«
psplay.c
Go to the documentation of this file.
1 /*
2  psplay.c - probabilistic splay tree
3 
4  Copyright (C)
5  2004, 2005, 2006, Christian Thaeter <chth@gmx.net>
6  Copyright (C) (contributed to CinelerraCV)
7  2007, 2008, Christian Thaeter <ct@pipapo.org>
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of
12  the License, or (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 
24 
29 #include "include/logging.h"
30 #include "lib/psplay.h"
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <nobug.h>
36 
37 //NOBUG_DEFINE_FLAG (psplay);
38 
39 #ifndef PSPLAY_TRAIL_DEPTH
40 #define PSPLAY_TRAIL_DEPTH 128
41 #endif
42 
43 /*
44  probabilistic distribution, this are the direct splay equations used to determine if to splay
45  or break out of the splaying algorithm.
46 
47  useable variables/functions are:
48  self->log2 - log2 of the tree elements, this would be the depth of a fully balanced tree
49  splayfactor - user defined weigth for splaying, we define '100' to be the default
50  depth - depth of the current node in the tree
51  trail->dir - dervitation from tree center
52  psplay_fast_prng () - returns a prng in the range 1...2^31
53 */
54 
55 #define PSPLAY_FORMULA (self->log2*100/(depth + (psplay_fast_prng () & 63)) + trail->dir) * splayfactor
56 
57 #ifndef PSPLAY_PROB_ZIGZIG
58 #define PSPLAY_PROB_ZIGZIG 5000
59 #endif
60 #ifndef PSPLAY_PROB_ZIGZAG
61 #define PSPLAY_PROB_ZIGZAG 2500
62 #endif
63 
64 
65 
66 /* simple prng with 2^31-1 cycle */
67 static inline uint32_t psplay_fast_prng ()
68 {
69  static uint32_t rnd=0xbabeface;
70  return rnd = rnd<<1 ^ ((rnd >> 30) & 1) ^ ((rnd>>2) & 1);
71 }
72 
73 
74 PSplay
76 {
77  //NOBUG_INIT_FLAG (psplay);
78  TRACE (psplay_dbg);
79  REQUIRE (cmp);
80  REQUIRE (key);
81 
82  if (self)
83  {
84  self->tree = NULL;
85  self->found_parent = &self->tree;
86  self->cmp = cmp;
87  self->key = key;
88  self->del = del;
89  self->elem_cnt = 0;
90  self->log2 = 0;
91  }
92  return self;
93 }
94 
95 
96 PSplay
98 {
99  PSplay self = malloc (sizeof *self);
100  if (self)
101  {
102  psplay_init (self , cmp, key, del);
103  }
104  return self;
105 }
106 
107 
108 
109 PSplay
110 psplay_destroy (PSplay self)
111 {
112  TRACE (psplay_dbg);
113  if (self) while (self->tree)
114  {
115  PSplaynode n = psplay_remove (self, self->tree);
116  if (self->del)
117  self->del (n);
118  }
119  return self;
120 }
121 
122 
123 void
124 psplay_delete (PSplay self)
125 {
126  free (psplay_destroy (self));
127 }
128 
129 
130 PSplaynode
131 psplaynode_init (PSplaynode self)
132 {
133  if (self)
134  self->left = self->right = NULL;
135  return self;
136 }
137 
138 
139 
140 /*
141  Lookup operations (lookup and insert) record the path as they decend into the tree
142  this will allow bottom up splaying without storing 'up' pointers in the node.
143  The length of this trail (PSPLAY_TRAIL_DEPTH) also define the maximal limit on how much
144  a node can be splayed up giving some hard bound for the splay operation.
145 
146  General wisdom tells that top down splaying is more efficent to implement than bottom
147  up splaying. Nevertheless we do bottom up splaying here because we can decide
148  randomly on each level if we want to continue splaying or not. No splaying
149  is certainly more efficent than top-down splaying.
150 */
152 {
153  int dir;
154  unsigned depth;
155  PSplaynode* trail[PSPLAY_TRAIL_DEPTH];
156 };
157 
158 static inline unsigned
159 trailidx (unsigned n)
160 {
161  return n & (PSPLAY_TRAIL_DEPTH-1);
162 }
163 
164 
165 static inline void
166 psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor)
167 {
168  TRACE (psplay_dbg, "%p %u", self, splayfactor);
169 
170  if (trail->dir < 0) trail->dir = - trail->dir;
171 
172  for (unsigned lim = PSPLAY_TRAIL_DEPTH, depth = trail->depth; lim > 2 && depth > 2; lim-=2, depth-=2)
173  {
174  PSplaynode node = *trail->trail [trailidx (depth)];
175  PSplaynode parent = *trail->trail [trailidx (depth-1)];
176  PSplaynode grandparent = *trail->trail [trailidx (depth-2)];
177 
178  unsigned r = PSPLAY_FORMULA;
179  TRACE (psplay_dbg, "r is %u", r);
180 
181  if (parent == grandparent->left)
182  {
183  TRACE (psplay_dbg, "ZIG..");
184  if (node == parent->left)
185  {
186  TRACE (psplay_dbg, "..ZIG");
187  if (r < PSPLAY_PROB_ZIGZIG)
188  {
189  TRACE (psplay_dbg, "BREAK");
190  return;
191  }
192 
193  grandparent->left = parent->right;
194  parent->right = grandparent;
195 
196  parent->left = node->right;
197  node->right = parent;
198  }
199  else
200  {
201  TRACE (psplay_dbg, "..ZAG");
202  if (r < PSPLAY_PROB_ZIGZAG)
203  {
204  TRACE (psplay_dbg, "BREAK");
205  return;
206  }
207 
208  parent->right = node->left;
209  node->left = parent;
210 
211  grandparent->left = node->right;
212  node->right = grandparent;
213  }
214  }
215  else
216  {
217  TRACE (psplay_dbg, "ZAG..");
218  if (node == parent->left)
219  {
220  TRACE (psplay_dbg, "..ZIG");
221  if (r < PSPLAY_PROB_ZIGZAG)
222  {
223  TRACE (psplay_dbg, "BREAK");
224  return;
225  }
226 
227  parent->left = node->right;
228  node->right = parent;
229 
230  grandparent->right = node->left;
231  node->left = grandparent;
232  }
233  else
234  {
235  TRACE (psplay_dbg, "..ZAG");
236  if (r < PSPLAY_PROB_ZIGZIG)
237  {
238  TRACE (psplay_dbg, "BREAK");
239  return;
240  }
241 
242  grandparent->right = parent->left;
243  parent->left = grandparent;
244 
245  parent->right = node->left;
246  node->left = parent;
247  }
248  }
249  *trail->trail [trailidx (depth-2)] = node;
250  }
251 }
252 
253 
254 PSplaynode
255 psplay_insert (PSplay self, PSplaynode node, int splayfactor)
256 {
257  TRACE (psplay_dbg);
258  PSplaynode n = self->tree;
259  struct psplaytrail trail;
260 
261  trail.dir = 0;
262  trail.depth = 0;
263  trail.trail [0] = &self->tree;
264 
265  if (!n)
266  self->tree = node;
267  else
268  {
269  while (n != node)
270  {
271  int c;
272  c = self->cmp (self->key (node), self->key (n));
273  ++trail.depth;
274 
275  if (c < 0)
276  {
277  --trail.dir;
278  if (!n->left)
279  n->left = node;
280  trail.trail [trailidx (trail.depth)] = &n->left;
281  n = n->left;
282  }
283  else if (c > 0)
284  {
285  ++trail.dir;
286  if (!n->right)
287  n->right = node;
288  trail.trail [trailidx (trail.depth)] = &n->right;
289  n = n->right;
290  }
291  else
292  {
293  WARN (psplay_dbg, "dropping duplicate entry for psplay");
295  return NULL;
296  }
297  }
298  }
299  ++self->elem_cnt;
300  if (self->elem_cnt >= 1UL<<self->log2) ++self->log2;
301  if (splayfactor && trail.depth > 2)
302  psplay_splay (self, &trail, splayfactor);
303  return node;
304 }
305 
306 
307 
308 PSplaynode
309 psplay_find (PSplay self, const void* key, int splayfactor)
310 {
311  TRACE (psplay_dbg);
312  PSplaynode node = self->tree;
313  struct psplaytrail trail;
314  trail.dir = 0;
315  trail.depth = 0;
316  trail.trail [0] = &self->tree;
317 
318  while (node)
319  {
320  int c;
321  c = self->cmp (key, self->key (node));
322  ++trail.depth;
323 
324  if (c < 0)
325  {
326  --trail.dir;
327  trail.trail [trailidx (trail.depth)] = &node->left;
328  node = node->left;
329  }
330  else if (c > 0)
331  {
332  ++trail.dir;
333  trail.trail [trailidx (trail.depth)] = &node->right;
334  node = node->right;
335  }
336  else
337  {
338  self->found_parent = trail.trail [trailidx (--trail.depth)];
339  break;
340  }
341  }
342  if (node && splayfactor && trail.depth > 2)
343  psplay_splay (self, &trail, splayfactor);
344  return node;
345 }
346 
347 
348 PSplaynode
349 psplay_remove (PSplay self, PSplaynode node)
350 {
351  TRACE (psplay_dbg);
352  if (!node) return NULL;
353 
354  PSplaynode* r = self->found_parent;
355 
356  while (*r != node)
357  {
358  if (!psplay_find (self, self->key (node), 0))
359  {
360  WARN (psplay_dbg, "node %p is not in splay tree %p", node, self);
361  return NULL;
362  }
363  r = self->found_parent;
364  }
365 
366  if (!node->left)
367  *r = node->right;
368  else if (!node->right)
369  *r = node->left;
370  else
371  {
372  PSplaynode i, iparent = NULL;
373  if (psplay_fast_prng()&1) /* 50% probability removing left or right wards */
374  {
375  for (i = node->left; i->right; iparent = i, i = i->right);
376  if (iparent)
377  iparent->right = i->left;
378  if (node->left != i)
379  i->left = node->left;
380  i->right = node->right;
381  }
382  else
383  {
384  for (i = node->right; i->left; iparent = i, i = i->left);
385  if (iparent)
386  iparent->left = i->right;
387  if (node->right != i)
388  i->right = node->right;
389  i->left = node->left;
390  }
391  *r = i;
392  }
393  --self->elem_cnt;
394  if (self->elem_cnt < 1UL<<self->log2) --self->log2;
395  return node;
396 }
397 
398 
399 PSplaynode
400 psplay_remove_key (PSplay self, void* key)
401 {
402  return psplay_remove (self, psplay_find (self, key, 0));
403 }
404 
405 
406 void
407 psplay_delete_node (PSplay self, PSplaynode node)
408 {
409  if (node)
410  self->del (psplay_remove (self, node));
411 }
412 
413 
414 void
415 psplay_delete_key (PSplay self, void* key)
416 {
417  PSplaynode node = psplay_find (self, key, 0);
418  psplay_delete_node (self, node);
419 }
420 
421 
422 
423 const psplay_delete_fn PSPLAY_CONT = (psplay_delete_fn)0x0;
424 const psplay_delete_fn PSPLAY_STOP = (psplay_delete_fn)0x1;
425 const psplay_delete_fn PSPLAY_REMOVE = (psplay_delete_fn)0x2;
426 
427 static int
428 psplay_handle (PSplay self, PSplaynode node, psplay_delete_fn res)
429 {
430  if (res == PSPLAY_CONT)
431  return 1;
432 
433  if (res == PSPLAY_STOP)
434  ;
435  else if (res == PSPLAY_REMOVE)
436  {
437  psplay_remove (self, node);
438  if (self->del)
439  self->del (node);
440  }
441  else
442  {
443  psplay_remove (self, node);
444  res (node);
445  }
446  return 0;
447 }
448 
449 
450 int
451 psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data)
452 {
453  if (!self->tree)
454  return 1;
455 
456  if (!node)
457  node = self->tree;
458 
459  psplay_delete_fn res;
460 
461  res = action (node, PSPLAY_PREORDER, level, data);
462  if (!psplay_handle (self, node, res))
463  return 0;
464 
465  if (node->left)
466  if (!psplay_walk (self, node->left, action, level+1, data))
467  return 0;
468 
469  res = action (node, PSPLAY_INORDER, level, data);
470  if (!psplay_handle (self, node, res))
471  return 0;
472 
473  if (node->right)
474  if (!psplay_walk (self, node->right, action, level+1, data))
475  return 0;
476 
477  res = action (node, PSPLAY_POSTORDER, level, data);
478  if (!psplay_handle (self, node, res))
479  return 0;
480 
481  return 1;
482 }
483 
484 
485 static psplay_delete_fn
486 psplay_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
487 {
488  FILE* fh = data;
489  static char* sp = " ";
490  if (level>40)
491  {
492  if (which == PSPLAY_PREORDER)
493  fprintf (fh, "%s ...\n", sp);
494  return PSPLAY_CONT;
495  }
496 
497  switch (which)
498  {
499  case PSPLAY_PREORDER:
500  fprintf (fh, "%s%p\n", sp+40-level, node);
501  if (node->left)
502  fprintf (fh, "%sleft %p\n", sp+40-level, node->left);
503  break;
504  case PSPLAY_INORDER:
505  if (node->right)
506  fprintf (fh, "%sright %p\n", sp+40-level, node->right);
507  break;
508  case PSPLAY_POSTORDER:
509  break;
510  }
511 
512  return PSPLAY_CONT;
513 }
514 
515 void
516 psplay_dump (PSplay self, FILE* dest)
517 {
518  fprintf (dest, "root %p\n", self->tree);
519  psplay_walk (self, NULL, psplay_print_node, 0, dest);
520 }
521 
522 
523 /*
524 // Local Variables:
525 // mode: C
526 // c-file-style: "gnu"
527 // indent-tabs-mode: nil
528 // End:
529 */
PSplay psplay_destroy(PSplay self)
Destroy a splay tree Frees all elements and associated resources of a splay tree. ...
Definition: psplay.c:110
psplay_delete_fn(* psplay_action_fn)(PSplaynode node, const enum psplay_order_enum which, int level, void *data)
Traverse a splay tree Traversing a tree calls a user supplied action three times An &#39;action&#39; must not...
Definition: psplay.h:265
PSplay psplay_init(PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del)
Initialize a splay tree.
Definition: psplay.c:75
const void *(* psplay_key_fn)(const PSplaynode node)
Retrieve the key from a user datastructure.
Definition: psplay.h:82
This header is for including and configuring NoBug.
PSplaynode psplay_find(PSplay self, const void *key, int splayfactor)
Find a element in a splay tree.
Definition: psplay.c:309
PSplaynode psplay_insert(PSplay self, PSplaynode node, int splayfactor)
Insert a element into a splay tree.
Definition: psplay.c:255
void psplay_delete(PSplay self)
Delete a splay tree Frees all elements and associated resources of a splay tree and then itseld...
Definition: psplay.c:124
PSplay psplay_new(psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del)
Allocate a splay tree.
Definition: psplay.c:97
Probabilistic splay tree.
int(* psplay_cmp_fn)(const void *a, const void *b)
Function use to compare keys.
Definition: psplay.h:64
PSplaynode psplay_remove(PSplay self, PSplaynode node)
Remove a node from a splay tree.
Definition: psplay.c:349
int psplay_walk(PSplay self, PSplaynode node, psplay_action_fn action, int level, void *data)
Start a tree traversal.
Definition: psplay.c:451
PSplaynode psplay_remove_key(PSplay self, void *key)
Remove a node by key from a splay tree.
Definition: psplay.c:400
void psplay_delete_key(PSplay self, void *key)
Delete a node by key from a splay tree.
Definition: psplay.c:415
PSplaynode psplaynode_init(PSplaynode self)
Initialise a splay tree node The user has to place this nodes within his datastructure and must Initi...
Definition: psplay.c:131
void(* psplay_delete_fn)(PSplaynode node)
Destructor for user defined data Called when an element got removed from a splay tree.
Definition: psplay.h:74
void psplay_delete_node(PSplay self, PSplaynode node)
Delete a node from a splay tree.
Definition: psplay.c:407