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