Leptonica  1.77.0
Image processing and image analysis suite
rbtree.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
27 /*
28  * Modified from the excellent code here:
29  * http://en.literateprograms.org/Red-black_tree_(C)?oldid=19567
30  * which has been placed in the public domain under the Creative Commons
31  * CC0 1.0 waiver (http://creativecommons.org/publicdomain/zero/1.0/).
32  */
33 
74 #include "allheaders.h"
75 
76  /* The node color enum is only needed in the rbtree implementation */
77 enum {
78  L_RED_NODE = 1,
79  L_BLACK_NODE = 2
80 };
81 
82  /* This makes it simpler to read the code */
83 typedef L_RBTREE_NODE node;
84 
85  /* Lots of static helper functions */
86 static void destroy_helper(node *n);
87 static void count_helper(node *n, l_int32 *pcount);
88 static void print_tree_helper(FILE *fp, node *n, l_int32 keytype,
89  l_int32 indent);
90 
91 static l_int32 compareKeys(l_int32 keytype, RB_TYPE left, RB_TYPE right);
92 
93 static node *grandparent(node *n);
94 static node *sibling(node *n);
95 static node *uncle(node *n);
96 static l_int32 node_color(node *n);
97 static node *new_node(RB_TYPE key, RB_TYPE value, l_int32 node_color,
98  node *left, node *right);
99 static node *lookup_node(L_RBTREE *t, RB_TYPE key);
100 static void rotate_left(L_RBTREE *t, node *n);
101 static void rotate_right(L_RBTREE *t, node *n);
102 static void replace_node(L_RBTREE *t, node *oldn, node *newn);
103 static void insert_case1(L_RBTREE *t, node *n);
104 static void insert_case2(L_RBTREE *t, node *n);
105 static void insert_case3(L_RBTREE *t, node *n);
106 static void insert_case4(L_RBTREE *t, node *n);
107 static void insert_case5(L_RBTREE *t, node *n);
108 static node *maximum_node(node *root);
109 static void delete_case1(L_RBTREE *t, node *n);
110 static void delete_case2(L_RBTREE *t, node *n);
111 static void delete_case3(L_RBTREE *t, node *n);
112 static void delete_case4(L_RBTREE *t, node *n);
113 static void delete_case5(L_RBTREE *t, node *n);
114 static void delete_case6(L_RBTREE *t, node *n);
115 static void verify_properties(L_RBTREE *t);
116 
117 #ifndef NO_CONSOLE_IO
118 #define VERIFY_RBTREE 0 /* only for debugging */
119 #endif /* ~NO_CONSOLE_IO */
120 
121 
122 /* ------------------------------------------------------------- *
123  * Interface to Red-black Tree *
124  * ------------------------------------------------------------- */
131 L_RBTREE *
132 l_rbtreeCreate(l_int32 keytype)
133 {
134  PROCNAME("l_rbtreeCreate");
135 
136  if (keytype != L_INT_TYPE && keytype != L_UINT_TYPE &&
137  keytype != L_FLOAT_TYPE && keytype)
138  return (L_RBTREE *)ERROR_PTR("invalid keytype", procName, NULL);
139 
140  L_RBTREE *t = (L_RBTREE *)LEPT_CALLOC(1, sizeof(L_RBTREE));
141  t->keytype = keytype;
142  verify_properties(t);
143  return t;
144 }
145 
153 RB_TYPE *
155  RB_TYPE key)
156 {
157  PROCNAME("l_rbtreeLookup");
158 
159  if (!t)
160  return (RB_TYPE *)ERROR_PTR("tree is null\n", procName, NULL);
161 
162  node *n = lookup_node(t, key);
163  return n == NULL ? NULL : &n->value;
164 }
165 
180 void
182  RB_TYPE key,
183  RB_TYPE value)
184 {
185 node *n, *inserted_node;
186 
187  PROCNAME("l_rbtreeInsert");
188 
189  if (!t) {
190  L_ERROR("tree is null\n", procName);
191  return;
192  }
193 
194  inserted_node = new_node(key, value, L_RED_NODE, NULL, NULL);
195  if (t->root == NULL) {
196  t->root = inserted_node;
197  } else {
198  n = t->root;
199  while (1) {
200  int comp_result = compareKeys(t->keytype, key, n->key);
201  if (comp_result == 0) {
202  n->value = value;
203  LEPT_FREE(inserted_node);
204  return;
205  } else if (comp_result < 0) {
206  if (n->left == NULL) {
207  n->left = inserted_node;
208  break;
209  } else {
210  n = n->left;
211  }
212  } else { /* comp_result > 0 */
213  if (n->right == NULL) {
214  n->right = inserted_node;
215  break;
216  } else {
217  n = n->right;
218  }
219  }
220  }
221  inserted_node->parent = n;
222  }
223  insert_case1(t, inserted_node);
224  verify_properties(t);
225 }
226 
234 void
236  RB_TYPE key)
237 {
238 node *n, *child;
239 
240  PROCNAME("l_rbtreeDelete");
241 
242  if (!t) {
243  L_ERROR("tree is null\n", procName);
244  return;
245  }
246 
247  n = lookup_node(t, key);
248  if (n == NULL) return; /* Key not found, do nothing */
249  if (n->left != NULL && n->right != NULL) {
250  /* Copy key/value from predecessor and then delete it instead */
251  node *pred = maximum_node(n->left);
252  n->key = pred->key;
253  n->value = pred->value;
254  n = pred;
255  }
256 
257  /* n->left == NULL || n->right == NULL */
258  child = n->right == NULL ? n->left : n->right;
259  if (node_color(n) == L_BLACK_NODE) {
260  n->color = node_color(child);
261  delete_case1(t, n);
262  }
263  replace_node(t, n, child);
264  if (n->parent == NULL && child != NULL) /* root should be black */
265  child->color = L_BLACK_NODE;
266  LEPT_FREE(n);
267 
268  verify_properties(t);
269 }
270 
282 void
284 {
285 node *n;
286 
287  if (!pt) return;
288  if (*pt == NULL) return;
289  n = (*pt)->root;
290  destroy_helper(n);
291  LEPT_FREE(*pt);
292  *pt = NULL;
293  return;
294 }
295 
296  /* postorder DFS */
297 static void
298 destroy_helper(node *n)
299 {
300  if (!n) return;
301  destroy_helper(n->left);
302  destroy_helper(n->right);
303  LEPT_FREE(n);
304 }
305 
319 {
320 node *n;
321 
322  PROCNAME("l_rbtreeGetFirst");
323 
324  if (!t)
325  return (L_RBTREE_NODE *)ERROR_PTR("tree is null", procName, NULL);
326  if (t->root == NULL) {
327  L_INFO("tree is empty\n", procName);
328  return NULL;
329  }
330 
331  /* Just go down the left side as far as possible */
332  n = t->root;
333  while (n && n->left)
334  n = n->left;
335  return n;
336 }
337 
354 {
355  PROCNAME("l_rbtreeGetNext");
356 
357  if (!n)
358  return (L_RBTREE_NODE *)ERROR_PTR("n not defined", procName, NULL);
359 
360  /* If there is a right child, go to it, and then go left all the
361  * way to the end. Otherwise go up to the parent; continue upward
362  * as long as you're on the right branch, but stop at the parent
363  * when you hit it from the left branch. */
364  if (n->right) {
365  n = n->right;
366  while (n->left)
367  n = n->left;
368  return n;
369  } else {
370  while (n->parent && n->parent->right == n)
371  n = n->parent;
372  return n->parent;
373  }
374 }
375 
389 {
390 node *n;
391 
392  PROCNAME("l_rbtreeGetLast");
393 
394  if (!t)
395  return (L_RBTREE_NODE *)ERROR_PTR("tree is null", procName, NULL);
396  if (t->root == NULL) {
397  L_INFO("tree is empty\n", procName);
398  return NULL;
399  }
400 
401  /* Just go down the right side as far as possible */
402  n = t->root;
403  while (n && n->right)
404  n = n->right;
405  return n;
406 }
407 
424 {
425  PROCNAME("l_rbtreeGetPrev");
426 
427  if (!n)
428  return (L_RBTREE_NODE *)ERROR_PTR("n not defined", procName, NULL);
429 
430  /* If there is a left child, go to it, and then go right all the
431  * way to the end. Otherwise go up to the parent; continue upward
432  * as long as you're on the left branch, but stop at the parent
433  * when you hit it from the right branch. */
434  if (n->left) {
435  n = n->left;
436  while (n->right)
437  n = n->right;
438  return n;
439  } else {
440  while (n->parent && n->parent->left == n)
441  n = n->parent;
442  return n->parent;
443  }
444 }
445 
452 l_int32
454 {
455 l_int32 count = 0;
456 node *n;
457 
458  if (!t) return 0;
459  n = t->root;
460  count_helper(n, &count);
461  return count;
462 }
463 
464  /* preorder DFS */
465 static void
466 count_helper(node *n, l_int32 *pcount)
467 {
468  if (n)
469  (*pcount)++;
470  else
471  return;
472 
473  count_helper(n->left, pcount);
474  count_helper(n->right, pcount);
475 }
476 
477 
485 void
486 l_rbtreePrint(FILE *fp,
487  L_RBTREE *t)
488 {
489  PROCNAME("l_rbtreePrint");
490  if (!fp) {
491  L_ERROR("stream not defined\n", procName);
492  return;
493  }
494  if (!t) {
495  L_ERROR("tree not defined\n", procName);
496  return;
497  }
498 
499  print_tree_helper(fp, t->root, t->keytype, 0);
500  fprintf(fp, "\n");
501 }
502 
503 #define INDENT_STEP 4
504 
505 static void
506 print_tree_helper(FILE *fp,
507  node *n,
508  l_int32 keytype,
509  l_int32 indent)
510 {
511 l_int32 i;
512 
513  if (n == NULL) {
514  fprintf(fp, "<empty tree>");
515  return;
516  }
517  if (n->right != NULL) {
518  print_tree_helper(fp, n->right, keytype, indent + INDENT_STEP);
519  }
520  for (i = 0; i < indent; i++)
521  fprintf(fp, " ");
522  if (n->color == L_BLACK_NODE) {
523  if (keytype == L_INT_TYPE)
524  fprintf(fp, "%lld\n", n->key.itype);
525  else if (keytype == L_UINT_TYPE)
526  fprintf(fp, "%llx\n", n->key.utype);
527  else if (keytype == L_FLOAT_TYPE)
528  fprintf(fp, "%f\n", n->key.ftype);
529  } else {
530  if (keytype == L_INT_TYPE)
531  fprintf(fp, "<%lld>\n", n->key.itype);
532  else if (keytype == L_UINT_TYPE)
533  fprintf(fp, "<%llx>\n", n->key.utype);
534  else if (keytype == L_FLOAT_TYPE)
535  fprintf(fp, "<%f>\n", n->key.ftype);
536  }
537  if (n->left != NULL) {
538  print_tree_helper(fp, n->left, keytype, indent + INDENT_STEP);
539  }
540 }
541 
542 
543 /* ------------------------------------------------------------- *
544  * Static key comparison function *
545  * ------------------------------------------------------------- */
546 static l_int32
547 compareKeys(l_int32 keytype,
548  RB_TYPE left,
549  RB_TYPE right)
550 {
551 static char procName[] = "compareKeys";
552 
553  if (keytype == L_INT_TYPE) {
554  if (left.itype < right.itype)
555  return -1;
556  else if (left.itype > right.itype)
557  return 1;
558  else { /* equality */
559  return 0;
560  }
561  } else if (keytype == L_UINT_TYPE) {
562  if (left.utype < right.utype)
563  return -1;
564  else if (left.utype > right.utype)
565  return 1;
566  else { /* equality */
567  return 0;
568  }
569  } else if (keytype == L_FLOAT_TYPE) {
570  if (left.ftype < right.ftype)
571  return -1;
572  else if (left.ftype > right.ftype)
573  return 1;
574  else { /* equality */
575  return 0;
576  }
577  } else {
578  L_ERROR("unknown keytype %d\n", procName, keytype);
579  return 0;
580  }
581 }
582 
583 
584 /* ------------------------------------------------------------- *
585  * Static red-black tree helpers *
586  * ------------------------------------------------------------- */
587 static node *grandparent(node *n) {
588  if (!n || !n->parent || !n->parent->parent) {
589  L_ERROR("root and child of root have no grandparent\n", "grandparent");
590  return NULL;
591  }
592  return n->parent->parent;
593 }
594 
595 static node *sibling(node *n) {
596  if (!n || !n->parent) {
597  L_ERROR("root has no sibling\n", "sibling");
598  return NULL;
599  }
600  if (n == n->parent->left)
601  return n->parent->right;
602  else
603  return n->parent->left;
604 }
605 
606 static node *uncle(node *n) {
607  if (!n || !n->parent || !n->parent->parent) {
608  L_ERROR("root and child of root have no uncle\n", "uncle");
609  return NULL;
610  }
611  return sibling(n->parent);
612 }
613 
614 static l_int32 node_color(node *n) {
615  return n == NULL ? L_BLACK_NODE : n->color;
616 }
617 
618 
619 static node *new_node(RB_TYPE key, RB_TYPE value, l_int32 node_color,
620  node *left, node *right) {
621  node *result = (node *)LEPT_CALLOC(1, sizeof(node));
622  result->key = key;
623  result->value = value;
624  result->color = node_color;
625  result->left = left;
626  result->right = right;
627  if (left != NULL) left->parent = result;
628  if (right != NULL) right->parent = result;
629  result->parent = NULL;
630  return result;
631 }
632 
633 static node *lookup_node(L_RBTREE *t, RB_TYPE key) {
634  node *n = t->root;
635  while (n != NULL) {
636  int comp_result = compareKeys(t->keytype, key, n->key);
637  if (comp_result == 0) {
638  return n;
639  } else if (comp_result < 0) {
640  n = n->left;
641  } else { /* comp_result > 0 */
642  n = n->right;
643  }
644  }
645  return n;
646 }
647 
648 static void rotate_left(L_RBTREE *t, node *n) {
649  node *r = n->right;
650  replace_node(t, n, r);
651  n->right = r->left;
652  if (r->left != NULL) {
653  r->left->parent = n;
654  }
655  r->left = n;
656  n->parent = r;
657 }
658 
659 static void rotate_right(L_RBTREE *t, node *n) {
660  node *L = n->left;
661  replace_node(t, n, L);
662  n->left = L->right;
663  if (L->right != NULL) {
664  L->right->parent = n;
665  }
666  L->right = n;
667  n->parent = L;
668 }
669 
670 static void replace_node(L_RBTREE *t, node *oldn, node *newn) {
671  if (oldn->parent == NULL) {
672  t->root = newn;
673  } else {
674  if (oldn == oldn->parent->left)
675  oldn->parent->left = newn;
676  else
677  oldn->parent->right = newn;
678  }
679  if (newn != NULL) {
680  newn->parent = oldn->parent;
681  }
682 }
683 
684 static void insert_case1(L_RBTREE *t, node *n) {
685  if (n->parent == NULL)
686  n->color = L_BLACK_NODE;
687  else
688  insert_case2(t, n);
689 }
690 
691 static void insert_case2(L_RBTREE *t, node *n) {
692  if (node_color(n->parent) == L_BLACK_NODE)
693  return; /* Tree is still valid */
694  else
695  insert_case3(t, n);
696 }
697 
698 static void insert_case3(L_RBTREE *t, node *n) {
699  if (node_color(uncle(n)) == L_RED_NODE) {
700  n->parent->color = L_BLACK_NODE;
701  uncle(n)->color = L_BLACK_NODE;
702  grandparent(n)->color = L_RED_NODE;
703  insert_case1(t, grandparent(n));
704  } else {
705  insert_case4(t, n);
706  }
707 }
708 
709 static void insert_case4(L_RBTREE *t, node *n) {
710  if (n == n->parent->right && n->parent == grandparent(n)->left) {
711  rotate_left(t, n->parent);
712  n = n->left;
713  } else if (n == n->parent->left && n->parent == grandparent(n)->right) {
714  rotate_right(t, n->parent);
715  n = n->right;
716  }
717  insert_case5(t, n);
718 }
719 
720 static void insert_case5(L_RBTREE *t, node *n) {
721  n->parent->color = L_BLACK_NODE;
722  grandparent(n)->color = L_RED_NODE;
723  if (n == n->parent->left && n->parent == grandparent(n)->left) {
724  rotate_right(t, grandparent(n));
725  } else if (n == n->parent->right && n->parent == grandparent(n)->right) {
726  rotate_left(t, grandparent(n));
727  } else {
728  L_ERROR("identity confusion\n", "insert_case5");
729  }
730 }
731 
732 static node *maximum_node(node *n) {
733  if (!n) {
734  L_ERROR("n not defined\n", "maximum_node");
735  return NULL;
736  }
737  while (n->right != NULL) {
738  n = n->right;
739  }
740  return n;
741 }
742 
743 static void delete_case1(L_RBTREE *t, node *n) {
744  if (n->parent == NULL)
745  return;
746  else
747  delete_case2(t, n);
748 }
749 
750 static void delete_case2(L_RBTREE *t, node *n) {
751  if (node_color(sibling(n)) == L_RED_NODE) {
752  n->parent->color = L_RED_NODE;
753  sibling(n)->color = L_BLACK_NODE;
754  if (n == n->parent->left)
755  rotate_left(t, n->parent);
756  else
757  rotate_right(t, n->parent);
758  }
759  delete_case3(t, n);
760 }
761 
762 static void delete_case3(L_RBTREE *t, node *n) {
763  if (node_color(n->parent) == L_BLACK_NODE &&
764  node_color(sibling(n)) == L_BLACK_NODE &&
765  node_color(sibling(n)->left) == L_BLACK_NODE &&
766  node_color(sibling(n)->right) == L_BLACK_NODE) {
767  sibling(n)->color = L_RED_NODE;
768  delete_case1(t, n->parent);
769  } else {
770  delete_case4(t, n);
771  }
772 }
773 
774 static void delete_case4(L_RBTREE *t, node *n) {
775  if (node_color(n->parent) == L_RED_NODE &&
776  node_color(sibling(n)) == L_BLACK_NODE &&
777  node_color(sibling(n)->left) == L_BLACK_NODE &&
778  node_color(sibling(n)->right) == L_BLACK_NODE) {
779  sibling(n)->color = L_RED_NODE;
780  n->parent->color = L_BLACK_NODE;
781  } else {
782  delete_case5(t, n);
783  }
784 }
785 
786 static void delete_case5(L_RBTREE *t, node *n) {
787  if (n == n->parent->left &&
788  node_color(sibling(n)) == L_BLACK_NODE &&
789  node_color(sibling(n)->left) == L_RED_NODE &&
790  node_color(sibling(n)->right) == L_BLACK_NODE) {
791  sibling(n)->color = L_RED_NODE;
792  sibling(n)->left->color = L_BLACK_NODE;
793  rotate_right(t, sibling(n));
794  } else if (n == n->parent->right &&
795  node_color(sibling(n)) == L_BLACK_NODE &&
796  node_color(sibling(n)->right) == L_RED_NODE &&
797  node_color(sibling(n)->left) == L_BLACK_NODE) {
798  sibling(n)->color = L_RED_NODE;
799  sibling(n)->right->color = L_BLACK_NODE;
800  rotate_left(t, sibling(n));
801  }
802  delete_case6(t, n);
803 }
804 
805 static void delete_case6(L_RBTREE *t, node *n) {
806  sibling(n)->color = node_color(n->parent);
807  n->parent->color = L_BLACK_NODE;
808  if (n == n->parent->left) {
809  if (node_color(sibling(n)->right) != L_RED_NODE) {
810  L_ERROR("right sibling is not RED", "delete_case6");
811  return;
812  }
813  sibling(n)->right->color = L_BLACK_NODE;
814  rotate_left(t, n->parent);
815  } else {
816  if (node_color(sibling(n)->left) != L_RED_NODE) {
817  L_ERROR("left sibling is not RED", "delete_case6");
818  return;
819  }
820  sibling(n)->left->color = L_BLACK_NODE;
821  rotate_right(t, n->parent);
822  }
823 }
824 
825 
826 /* ------------------------------------------------------------- *
827  * Debugging: verify if tree is valid *
828  * ------------------------------------------------------------- */
829 #if VERIFY_RBTREE
830 static void verify_property_1(node *root);
831 static void verify_property_2(node *root);
832 static void verify_property_4(node *root);
833 static void verify_property_5(node *root);
834 static void verify_property_5_helper(node *n, int black_count,
835  int* black_count_path);
836 #endif
837 
838 static void verify_properties(L_RBTREE *t) {
839 #if VERIFY_RBTREE
840  verify_property_1(t->root);
841  verify_property_2(t->root);
842  /* Property 3 is implicit */
843  verify_property_4(t->root);
844  verify_property_5(t->root);
845 #endif
846 }
847 
848 #if VERIFY_RBTREE
849 static void verify_property_1(node *n) {
850  if (node_color(n) != L_RED_NODE && node_color(n) != L_BLACK_NODE) {
851  L_ERROR("color neither RED nor BLACK\n", "verify_property_1");
852  return;
853  }
854  if (n == NULL) return;
855  verify_property_1(n->left);
856  verify_property_1(n->right);
857 }
858 
859 static void verify_property_2(node *root) {
860  if (node_color(root) != L_BLACK_NODE)
861  L_ERROR("root is not black!\n", "verify_property_2");
862 }
863 
864 static void verify_property_4(node *n) {
865  if (node_color(n) == L_RED_NODE) {
866  if (node_color(n->left) != L_BLACK_NODE ||
867  node_color(n->right) != L_BLACK_NODE ||
868  node_color(n->parent) != L_BLACK_NODE) {
869  L_ERROR("children & parent not all BLACK", "verify_property_4");
870  return;
871  }
872  }
873  if (n == NULL) return;
874  verify_property_4(n->left);
875  verify_property_4(n->right);
876 }
877 
878 static void verify_property_5(node *root) {
879  int black_count_path = -1;
880  verify_property_5_helper(root, 0, &black_count_path);
881 }
882 
883 static void verify_property_5_helper(node *n, int black_count,
884  int* path_black_count) {
885  if (node_color(n) == L_BLACK_NODE) {
886  black_count++;
887  }
888  if (n == NULL) {
889  if (*path_black_count == -1) {
890  *path_black_count = black_count;
891  } else if (*path_black_count != black_count) {
892  L_ERROR("incorrect black count", "verify_property_5_helper");
893  }
894  return;
895  }
896  verify_property_5_helper(n->left, black_count, path_black_count);
897  verify_property_5_helper(n->right, black_count, path_black_count);
898 }
899 #endif
void l_rbtreeDestroy(L_RBTREE **pt)
l_rbtreeDestroy()
Definition: rbtree.c:283
void l_rbtreePrint(FILE *fp, L_RBTREE *t)
l_rbtreePrint()
Definition: rbtree.c:486
L_RBTREE_NODE * l_rbtreeGetLast(L_RBTREE *t)
l_rbtreeGetLast()
Definition: rbtree.c:388
L_RBTREE * l_rbtreeCreate(l_int32 keytype)
l_rbtreeCreate()
Definition: rbtree.c:132
L_RBTREE_NODE * l_rbtreeGetFirst(L_RBTREE *t)
l_rbtreeGetFirst()
Definition: rbtree.c:318
L_RBTREE_NODE * l_rbtreeGetPrev(L_RBTREE_NODE *n)
l_rbtreeGetPrev()
Definition: rbtree.c:423
void l_rbtreeDelete(L_RBTREE *t, RB_TYPE key)
l_rbtreeDelete()
Definition: rbtree.c:235
void l_rbtreeInsert(L_RBTREE *t, RB_TYPE key, RB_TYPE value)
l_rbtreeInsert()
Definition: rbtree.c:181
RB_TYPE * l_rbtreeLookup(L_RBTREE *t, RB_TYPE key)
l_rbtreeLookup()
Definition: rbtree.c:154
L_RBTREE_NODE * l_rbtreeGetNext(L_RBTREE_NODE *n)
l_rbtreeGetNext()
Definition: rbtree.c:353
l_int32 l_rbtreeGetCount(L_RBTREE *t)
l_rbtreeGetCount()
Definition: rbtree.c:453
Definition: rbtree.h:61