2 psplay.c - probabilistic splay tree
5 2004, 2005, 2006, Christian Thaeter <chth@gmx.net>
6 Copyright (C) CinelerraCV
7 2007, Christian Thaeter <ct@pipapo.org>
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 the
12 License, or (at your option) any later version.
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.
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.
29 probabilistic distribution as n/255 chance of splaying
31 #ifndef PSPLAY_PROB_ZIG
32 /* already near root, only approx 6% splay probability */
33 #define PSPLAY_PROB_ZIG 16
35 /* approx 63% splay probability */
36 #ifndef PSPLAY_PROB_ZIGZIG
37 #define PSPLAY_PROB_ZIGZIG 160
39 /* zigzag reduces the tree by 1 level, approx 88% splay probability */
40 #ifndef PSPLAY_PROB_ZIGZAG
41 #define PSPLAY_PROB_ZIGZAG 224
46 /* simple prng with 2^31-1 cycle */
47 static inline uint32_t psplay_fast_prng ()
49 static uint32_t rnd=0xbabeface;
50 return rnd = rnd<<1 ^ ((rnd >> 30) & 1) ^ ((rnd>>2) & 1);
55 psplay_init_root (PSplayroot self, psplay_cmp_t cmp, psplay_delete_t delete)
61 self->delete = delete;
69 psplay_destroy_root (PSplayroot self)
71 if (self) while (self->tree)
73 PSplay n = psplay_remove (self, self->tree);
87 psplay_splay (PSplay* root, PSplay node)
91 PSplay p = node->up; // parent
92 PSplay g = p?p->up:NULL; // grandparent
102 if ((psplay_fast_prng()&0xFF) >= PSPLAY_PROB_ZIGZIG)
106 if (g->left) g->left->up = g;
109 p->left = node->right;
110 if (p->left) p->left->up = p;
119 if ((psplay_fast_prng()&0xFF) >= PSPLAY_PROB_ZIGZAG)
122 p->right = node->left;
123 if (p->right) p->right->up = p;
126 g->left = node->right;
127 if (g->left) g->left->up = g;
140 if ((psplay_fast_prng()&0xFF) >= PSPLAY_PROB_ZIGZAG)
143 p->left = node->right;
144 if (p->left) p->left->up = p;
147 g->right = node->left;
148 if (g->right) g->right->up = g;
157 if ((psplay_fast_prng()&0xFF) >= PSPLAY_PROB_ZIGZIG)
161 if (g->right) g->right->up = g;
164 p->right = node->left;
165 if (p->right) p->right->up = p;
176 if (node->up->left == g)
177 node->up->left = node;
179 node->up->right = node;
190 if ((psplay_fast_prng()&0xFF) >= PSPLAY_PROB_ZIG)
196 p->left = node->right;
197 if (p->left) p->left->up = p;
203 p->right = node->left;
204 if (p->right) p->right->up = p;
217 psplay_new (void * key)
219 return psplay_init (malloc (sizeof (psplay)), key);
224 psplay_init (PSplay self, const void* key)
229 self->up = self->left = self->right = NULL;
235 psplay_delete (PSplay node)
242 psplay_insert (PSplayroot root, PSplay node)
244 PSplay n = root->tree;
253 c = root->cmp (node->key, n->key);
276 psplay_splay (&root->tree, node);
284 psplay_find (PSplayroot root, void* key)
286 PSplay node = root->tree;
291 c = root->cmp (key, node->key);
299 psplay_splay (&root->tree, node);
308 psplay_remove (PSplayroot root, PSplay node)
310 if (!node) return NULL;
332 else if (!node->right)
342 if (psplay_fast_prng()&1) /* 50% probability removing left or right wards */
345 for (i = node->left; i->right; i = i->right);
347 i->right = node->right;
349 i->up->right = i->left;
356 i->left = node->left;
363 for (i = node->right; i->left; i = i->left);
365 i->left = node->left;
367 i->up->left = i->right;
370 i->right->up = i->up;
372 if (node->right != i)
374 i->right = node->right;
381 node->up = node->left = node->right = NULL;
387 Walking a tree calls a 'action' three times PSPLAY_PREORDER before visiting the left subtree,
388 PSPLAY_INORDER after visiting the left subtree and before the right subtree, PSPLAY_POSTORDER
389 finally after visiting the right subtree. Example: For to traverse the tree in order action
390 would only handle PSPLAY_INORDER.
391 This action returns PSLPLAY_CONT when the traversal of the tree shall continue.
392 An 'action' must not alter the tree itself but it can indicate aborting the tree traversal and
393 how the current node is handled by its return value:
395 just stops the traversal
397 stops the traversal and removes the current node, calling the delete handler registered in root
398 any other psplay_delete_t:
399 stops the traversal and removes the current node, calling the returned delete handler with it
401 const psplay_delete_t PSPLAY_CONT = (psplay_delete_t)0x0;
402 const psplay_delete_t PSPLAY_STOP = (psplay_delete_t)0x1;
403 const psplay_delete_t PSPLAY_REMOVE = (psplay_delete_t)0x2;
406 psplay_handle (PSplayroot root, PSplay node, psplay_delete_t res)
408 if (res == PSPLAY_CONT)
411 if (res == PSPLAY_STOP)
413 else if (res == PSPLAY_REMOVE)
415 psplay_remove (root, node);
421 psplay_remove (root, node);
429 psplay_walk (PSplayroot root, PSplay node, psplay_action_t action, int level, void* data)
439 res = action (node, PSPLAY_PREORDER, level, data);
440 if (!psplay_handle (root, node, res))
444 if (!psplay_walk (root, node->left, action, level+1, data))
447 res = action (node, PSPLAY_INORDER, level, data);
448 if (!psplay_handle (root, node, res))
452 if (!psplay_walk (root, node->right, action, level+1, data))
455 res = action (node, PSPLAY_POSTORDER, level, data);
456 if (!psplay_handle (root, node, res))
463 psplay_print_node (PSplay node, const enum psplay_order_e which, int level, void* data)
466 static char* sp = " ";
469 if (which == PSPLAY_PREORDER)
470 fprintf (fh, "%s ...\n", sp+40-level);
476 case PSPLAY_PREORDER:
477 fprintf (fh, "%s%p\n", sp+40-level, node);
478 fprintf (fh, "%skey %p (%.4s)\n", sp+40-level, (char*)node->key, node->key?(char*)node->key:"NULL");
479 fprintf (fh, "%sup %p\n", sp+40-level, node->up);
480 fprintf (fh, "%sleft %p\n", sp+40-level, node->left);
483 fprintf (fh, "%sright %p\n", sp+40-level, node->right);
485 case PSPLAY_POSTORDER:
493 psplay_dump (PSplayroot root, FILE* dest)
495 psplay_walk (root, NULL, psplay_print_node, 0, dest);
496 fprintf (dest, "\n");
499 int my_cmp (const void* a, const void* b)
501 return strcmp (a, b);
505 #ifdef PSPLAY_TESTMAIN
509 psplayroot root = PSPLAYROOT_INITIALIZER(my_cmp, NULL);
510 psplay_init_root (&root, my_cmp, psplay_delete);
512 psplay_insert (&root, psplay_new("foo"));
513 psplay_insert (&root, psplay_new("bar"));
514 psplay_insert (&root, psplay_new("baz"));
515 psplay_insert (&root, psplay_new("test"));
516 psplay_insert (&root, psplay_new("pap"));
517 psplay_insert (&root, psplay_new("qux"));
519 psplay_dump (&root, stdout);
521 PSplay f = psplay_find (&root, "baz");
522 printf ("found %p (%.4s)\n", f, f->key?(char*)f->key:"NULL");
523 psplay_dump (&root, stdout);
525 f = psplay_find (&root, "test");
526 printf ("found %p (%.4s)\n", f, f->key?(char*)f->key:"NULL");
527 psplay_dump (&root, stdout);
529 f = psplay_find (&root, "test");
530 printf ("found %p (%.4s)\n", f, f->key?(char*)f->key:"NULL");
531 psplay_dump (&root, stdout);
533 f = psplay_find (&root, "foo");
534 printf ("found %p (%.4s)\n", f, f->key?(char*)f->key:"NULL");
535 psplay_dump (&root, stdout);
538 psplay_delete (psplay_remove (&root, root.tree));
539 psplay_dump (&root, stdout);
541 psplay_delete (psplay_remove (&root, root.tree));
542 psplay_dump (&root, stdout);
544 psplay_delete (psplay_remove (&root, root.tree));
545 psplay_dump (&root, stdout);
547 printf ("destroying\n");
548 psplay_destroy_root (&root);
549 psplay_dump (&root, stdout);
551 psplay_delete (psplay_remove (&root, root.tree));
552 psplay_dump (&root, stdout);
554 psplay_delete (psplay_remove (&root, root.tree));
555 psplay_dump (&root, stdout);
557 psplay_delete (psplay_remove (&root, root.tree));
558 psplay_dump (&root, stdout);