libdict 1.0.7
Data Structure C Library
Loading...
Searching...
No Matches
pr_tree.c
Go to the documentation of this file.
1/*
2 * libdict -- internal path reduction tree implementation.
3 *
4 * Copyright (c) 2001-2014, Farooq Mela
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * cf. [Gonnet 1983], [Gonnet 1984]
30 */
31
32#include "pr_tree.h"
33
34#include "dict_private.h"
35#include "tree_common.h"
36
37typedef struct pr_node pr_node;
38struct pr_node {
40 unsigned weight;
41};
42
43#define WEIGHT(n) ((n) ? (n)->weight : 1)
44
48
52
53/* Vtable thunks. The vtable slot types take void*, and calling a function
54 * through a function-pointer type that is not compatible with the function's
55 * own type is undefined behaviour (C11 6.5.2.2p9), so each slot below gets a
56 * thunk with the exact slot signature instead of a cast. A cast would also
57 * hide a genuine signature mismatch. */
58static dict_itor* vt_pr_dict_itor_new(void* obj) { return pr_dict_itor_new(obj); }
59static dict_insert_result vt_pr_tree_insert(void* obj, void* key) { return pr_tree_insert(obj, key); }
60static dict_remove_result vt_pr_tree_remove(void* obj, const void* key) { return pr_tree_remove(obj, key); }
61static bool vt_pr_tree_select(void* obj, size_t n, const void** key, void** datum) { return pr_tree_select(obj, n, key, datum); }
62static bool vt_pr_tree_verify(const void* obj) { return pr_tree_verify(obj); }
63static bool vt_pr_itor_remove(void* itor) { return pr_itor_remove(itor); }
64
65static const dict_vtable pr_tree_vtable = {
66 true,
67 vt_pr_dict_itor_new,
69 vt_pr_tree_insert,
75 vt_pr_tree_remove,
78 vt_pr_tree_select,
80 vt_pr_tree_verify,
81};
82
83static const itor_vtable pr_tree_itor_vtable = {
100 vt_pr_itor_remove,
102};
103
104static unsigned fixup(pr_tree* tree, pr_node* node);
105static void rot_left(pr_tree* tree, pr_node* node);
106static void rot_right(pr_tree* tree, pr_node* node);
107static pr_node* node_new(void* key);
108
109pr_tree*
111{
112 ASSERT(cmp_func != NULL);
113
114 pr_tree* tree = MALLOC(sizeof(*tree));
115 if (tree) {
116 tree->root = NULL;
117 tree->count = 0;
118 tree->cmp_func = cmp_func;
119 tree->rotation_count = 0;
120 }
121 return tree;
122}
123
124dict*
126{
127 dict* dct = MALLOC(sizeof(*dct));
128 if (dct) {
129 if (!(dct->_object = pr_tree_new(cmp_func))) {
130 FREE(dct);
131 return NULL;
132 }
133 dct->_vtable = &pr_tree_vtable;
134 }
135 return dct;
136}
137
138size_t pr_tree_free(pr_tree* tree, dict_delete_func delete_func) { return tree_free(tree, delete_func); }
139void** pr_tree_search(pr_tree* tree, const void* key) { return tree_search(tree, key); }
140void** pr_tree_search_le(pr_tree* tree, const void* key) { return tree_search_le(tree, key); }
141void** pr_tree_search_lt(pr_tree* tree, const void* key) { return tree_search_lt(tree, key); }
142void** pr_tree_search_ge(pr_tree* tree, const void* key) { return tree_search_ge(tree, key); }
143void** pr_tree_search_gt(pr_tree* tree, const void* key) { return tree_search_gt(tree, key); }
144
145static unsigned
146fixup(pr_tree* tree, pr_node* node)
147{
148 /*
149 * The internal path length of a tree is defined as the sum of levels of
150 * all the tree's internal nodes. Path-reduction trees are similar to
151 * weight-balanced trees, except that rotations are only made when they can
152 * reduce the total internal path length of the tree. These particular
153 * trees are in the class BB[1/3], but because of these restrictions their
154 * performance is superior to BB[1/3] trees.
155 *
156 * Consider a node N.
157 * A single left rotation is performed when
158 * WEIGHT(n->rlink->rlink) > WEIGHT(n->llink)
159 * A right-left rotation is performed when
160 * WEIGHT(n->rlink->llink) > WEIGHT(n->llink)
161 *
162 * A single right rotation is performed when
163 * WEIGHT(n->llink->llink) > WEIGHT(n->rlink)
164 * A left-right rotation is performed when
165 * WEIGHT(n->llink->rlink) > WEIGHT(n->rlink)
166 *
167 * Although the worst case number of rotations for a single insertion or
168 * deletion is O(n), the amortized worst-case number of rotations is
169 * .44042lg(n) + O(1) for insertion, and .42062lg(n) + O(1) for deletion.
170 *
171 * Every rotating branch below recurses twice, once into each node whose
172 * subtree changed shape, so the recursion depth is bounded by the height
173 * of the tree.
174 */
175 unsigned rotations = 0;
176 const unsigned lweight = WEIGHT(node->llink);
177 const unsigned rweight = WEIGHT(node->rlink);
178 if (lweight < rweight) {
179 pr_node* r = node->rlink;
180 ASSERT(r != NULL);
181 if (WEIGHT(r->rlink) > lweight) { /* RR */
182 rot_left(tree, node);
183 rotations += 1;
184 rotations += fixup(tree, node);
185 /* Commenting the next line means we must make the weight
186 * verification condition in node_verify() less stringent. */
187 rotations += fixup(tree, r);
188 } else if (WEIGHT(r->llink) > lweight) { /* RL */
189 /* Rotate |r| right, then |node| left, with |rl| taking the place
190 * of |node| and having |node| and |r| as left and right children,
191 * respectively. */
192 pr_node* const rl = r->llink;
193 pr_node* const parent = node->parent;
194
195 pr_node* const a = rl->llink;
196 rl->llink = node;
197 node->parent = rl;
198 if ((node->rlink = a) != NULL)
199 a->parent = node;
200
201 pr_node* const b = rl->rlink;
202 rl->rlink = r;
203 r->parent = rl;
204 if ((r->llink = b) != NULL)
205 b->parent = r;
206
207 rl->parent = parent;
208 *(parent ? (parent->llink == node ? &parent->llink : &parent->rlink) : &tree->root) = rl;
209
210 node->weight += WEIGHT(a) - r->weight;
211 r->weight += WEIGHT(b) - rl->weight;
212 rl->weight = node->weight + r->weight;
213
214 /* A double rotation counts as two, matching the mirrored LR case
215 * below. */
216 rotations += 2;
217 rotations += fixup(tree, r);
218 rotations += fixup(tree, node);
219 }
220 } else if (lweight > rweight) {
221 pr_node* l = node->llink;
222 ASSERT(l != NULL);
223 if (WEIGHT(l->llink) > rweight) { /* LL */
224 rot_right(tree, node);
225 rotations += 1;
226 rotations += fixup(tree, node);
227 /* Commenting the next line means we must make the weight
228 * verification condition in node_verify() less stringent. */
229 rotations += fixup(tree, l);
230 } else if (WEIGHT(l->rlink) > rweight) { /* LR */
231 /* Rotate |l| left, then |node| right, with |lr| taking the place of
232 * |node| and having |l| and |node| as left and right children,
233 * respectively. */
234 pr_node* const lr = l->rlink;
235 pr_node* const parent = node->parent;
236
237 pr_node* const a = lr->llink;
238 lr->llink = l;
239 l->parent = lr;
240 if ((l->rlink = a) != NULL)
241 a->parent = l;
242
243 pr_node* const b = lr->rlink;
244 lr->rlink = node;
245 node->parent = lr;
246 if ((node->llink = b) != NULL)
247 b->parent = node;
248
249 lr->parent = parent;
250 *(parent ? (parent->llink == node ? &parent->llink : &parent->rlink) : &tree->root) = lr;
251
252 node->weight += WEIGHT(b) - l->weight;
253 l->weight += WEIGHT(a) - lr->weight;
254 lr->weight = node->weight + l->weight;
255
256 rotations += 2;
257 rotations += fixup(tree, l);
258 rotations += fixup(tree, node);
259 }
260 }
261 return rotations;
262}
263
266{
267 int cmp = 0;
268 pr_node* node = tree->root;
269 pr_node* parent = NULL;
270 while (node) {
271 cmp = tree->cmp_func(key, node->key);
272 if (cmp < 0) {
273 parent = node; node = node->llink;
274 } else if (cmp > 0) {
275 parent = node; node = node->rlink;
276 } else
277 return (dict_insert_result) { &node->datum, false };
278 }
279
280 pr_node* add = node_new(key);
281 if (!add)
282 return (dict_insert_result) { NULL, false };
283 if (!(add->parent = parent)) {
284 ASSERT(tree->count == 0);
285 ASSERT(tree->root == NULL);
286 tree->root = add;
287 } else {
288 if (cmp < 0)
289 parent->llink = add;
290 else
291 parent->rlink = add;
292
293 unsigned rotations = 0;
294 while ((node = parent) != NULL) {
295 parent = parent->parent;
296 ++node->weight;
297 rotations += fixup(tree, node);
298 }
299 tree->rotation_count += rotations;
300 }
301 tree->count++;
302 return (dict_insert_result) { &add->datum, true };
303}
304
305static void
306remove_node(pr_tree* tree, pr_node* node)
307{
308 if (node->llink && node->rlink) {
309 pr_node* out;
310 if (node->llink->weight > node->rlink->weight) {
311 out = tree_node_max(node->llink);
312 } else {
313 out = tree_node_min(node->rlink);
314 }
315 void* tmp;
316 SWAP(node->key, out->key, tmp);
317 SWAP(node->datum, out->datum, tmp);
318 node = out;
319 }
320 ASSERT(!node->llink || !node->rlink);
321 /* Splice in the node's only child, if any. */
322 pr_node* child = node->llink ? node->llink : node->rlink;
323 pr_node* parent = node->parent;
324 if (child)
325 child->parent = parent;
326 *(parent ? (parent->llink == node ? &parent->llink : &parent->rlink) : &tree->root) = child;
327 FREE(node);
328 tree->count--;
329 /* Now move up the tree, decrementing weights. */
330 unsigned rotations = 0;
331 while (parent) {
332 --parent->weight;
333 pr_node* up = parent->parent;
334 rotations += fixup(tree, parent);
335 parent = up;
336 }
337 tree->rotation_count += rotations;
338}
339
341pr_tree_remove(pr_tree* tree, const void* key)
342{
343 pr_node* node = tree_search_node(tree, key);
344 if (!node)
345 return (dict_remove_result) { NULL, NULL, false };
346 dict_remove_result result = { node->key, node->datum, true };
347 remove_node(tree, node);
348 return result;
349}
350
351size_t pr_tree_clear(pr_tree* tree, dict_delete_func delete_func) { return tree_clear(tree, delete_func); }
352
353size_t
355{
356 return tree_traverse(tree, visit, user_data);
357}
358
359bool
360pr_tree_select(pr_tree* tree, size_t n, const void** key, void** datum)
361{
362 if (n >= tree->count) {
363 if (key)
364 *key = NULL;
365 if (datum)
366 *datum = NULL;
367 return false;
368 }
369 pr_node* node = tree->root;
370 for (;;) {
371 const unsigned nw = WEIGHT(node->llink);
372 if (n + 1 >= nw) {
373 if (n + 1 == nw) {
374 if (key)
375 *key = node->key;
376 if (datum)
377 *datum = node->datum;
378 return true;
379 }
380 n -= nw;
381 node = node->rlink;
382 } else {
383 node = node->llink;
384 }
385 }
386}
387
388size_t pr_tree_count(const pr_tree* tree) { return tree_count(tree); }
392
393static pr_node*
394node_new(void* key)
395{
396 pr_node* node = MALLOC(sizeof(*node));
397 if (node) {
398 node->key = key;
399 node->datum = NULL;
400 node->parent = NULL;
401 node->llink = NULL;
402 node->rlink = NULL;
403 node->weight = 2;
404 }
405 return node;
406}
407
408/*
409 * rot_left(T, B):
410 *
411 * / /
412 * B D
413 * / \ / \
414 * A D ==> B E
415 * / \ / \
416 * C E A C
417 *
418 * Only the weights of B and B's new parent D need to be readjusted.
419 */
420static void
421rot_left(pr_tree* tree, pr_node *node)
422{
423 ASSERT(node->rlink != NULL);
424
425 pr_node* rlink = node->rlink;
427
428 node->weight = WEIGHT(node->llink) + WEIGHT(node->rlink);
429 rlink->weight = node->weight + WEIGHT(rlink->rlink);
430}
431
432/*
433 * rot_right(T, D):
434 *
435 * / /
436 * D B
437 * / \ / \
438 * B E ==> A D
439 * / \ / \
440 * A C C E
441 *
442 * Only the weights of D and D's new parent B need to be readjusted.
443 */
444static void
445rot_right(pr_tree* tree, pr_node* node)
446{
447 ASSERT(node->llink != NULL);
448
449 pr_node* llink = node->llink;
451
452 node->weight = WEIGHT(node->llink) + WEIGHT(node->rlink);
453 llink->weight = WEIGHT(llink->llink) + node->weight;
454}
455
456static bool
457node_verify(const pr_tree* tree, const pr_node* parent, const pr_node* node,
458 const void* lower, const void* upper, size_t* count)
459{
460 if (!parent) {
461 VERIFY(tree->root == node);
462 } else {
463 VERIFY(parent->llink == node || parent->rlink == node);
464 }
465 if (node) {
466 VERIFY(node->parent == parent);
467 /* Global BST ordering. Comparing a node only against its immediate
468 * parent would accept an entire subtree placed on the wrong side:
469 * root 5, 5->llink 3, 3->rlink 7 passes every parent-local check yet
470 * makes key 7 unreachable from the root. */
471 if (lower)
472 VERIFY(tree->cmp_func(lower, node->key) < 0);
473 if (upper)
474 VERIFY(tree->cmp_func(upper, node->key) > 0);
475 pr_node* l = node->llink;
476 pr_node* r = node->rlink;
477 *count += 1;
478 if (!node_verify(tree, node, l, lower, node->key, count) ||
479 !node_verify(tree, node, r, node->key, upper, count))
480 return false;
481 unsigned lweight = WEIGHT(l);
482 unsigned rweight = WEIGHT(r);
483 VERIFY(node->weight == lweight + rweight);
484 if (r && rweight > lweight) {
485 VERIFY(WEIGHT(r->rlink) <= lweight);
486 VERIFY(WEIGHT(r->llink) <= lweight);
487 } else if (l && lweight > rweight) {
488 VERIFY(WEIGHT(l->llink) <= rweight);
489 VERIFY(WEIGHT(l->rlink) <= rweight);
490 }
491 }
492 return true;
493}
494
495bool
497{
498 if (tree->root) {
499 VERIFY(tree->count > 0);
500 } else {
501 VERIFY(tree->count == 0);
502 }
503 size_t count = 0;
504 if (!node_verify(tree, NULL, tree->root, NULL, NULL, &count))
505 return false;
506 VERIFY(tree->count == count);
507 return true;
508}
509
510pr_itor*
512{
513 pr_itor* itor = MALLOC(sizeof(*itor));
514 if (itor) {
515 itor->tree = tree;
516 itor->node = NULL;
517 }
518 return itor;
519}
520
523{
524 dict_itor* itor = MALLOC(sizeof(*itor));
525 if (itor) {
526 if (!(itor->_itor = pr_itor_new(tree))) {
527 FREE(itor);
528 return NULL;
529 }
530 itor->_vtable = &pr_tree_itor_vtable;
531 }
532 return itor;
533}
534
536bool pr_itor_valid(const pr_itor* itor) { return tree_iterator_valid(itor); }
538bool pr_itor_next(pr_itor* itor) { return tree_iterator_next(itor); }
539bool pr_itor_prev(pr_itor* itor) { return tree_iterator_prev(itor); }
540bool pr_itor_nextn(pr_itor* itor, size_t count) { return tree_iterator_nextn(itor, count); } /* TODO: speed up */
541bool pr_itor_prevn(pr_itor* itor, size_t count) { return tree_iterator_prevn(itor, count); } /* TODO: speed up */
542bool pr_itor_first(pr_itor* itor) { return tree_iterator_first(itor); }
543bool pr_itor_last(pr_itor* itor) { return tree_iterator_last(itor); }
544bool pr_itor_search(pr_itor* itor, const void* key) { return tree_iterator_search(itor, key); }
545bool pr_itor_search_le(pr_itor* itor, const void* key) { return tree_iterator_search_le(itor, key); }
546bool pr_itor_search_lt(pr_itor* itor, const void* key) { return tree_iterator_search_lt(itor, key); }
547bool pr_itor_search_ge(pr_itor* itor, const void* key) { return tree_iterator_search_ge(itor, key); }
548bool pr_itor_search_gt(pr_itor* itor, const void* key) { return tree_iterator_search_gt(itor, key); }
549const void* pr_itor_key(const pr_itor* itor) { return tree_iterator_key(itor); }
550void** pr_itor_datum(pr_itor* itor) { return tree_iterator_datum(itor); }
551int pr_itor_compare(const pr_itor* i1, const pr_itor* i2) { return tree_iterator_compare(i1, i2); }
552
553bool
555{
556 if (!it->node)
557 return false;
558 remove_node(it->tree, it->node);
559 it->node = NULL;
560 return true;
561}
int(* dict_compare_func)(const void *, const void *)
A pointer to a function that compares two keys.
Definition dict.h:59
void(* dict_delete_func)(void *, void *)
A pointer to a function that is called when a key-value pair gets removed from a dictionary.
Definition dict.h:62
bool(* dict_visit_func)(const void *, void *, void *)
A pointer to a function used for iterating over dictionary contents.
Definition dict.h:64
#define FREE(p)
#define ASSERT(expr)
#define VERIFY(expr)
#define MALLOC(n)
#define SWAP(a, b, v)
pr_tree * pr_tree_new(dict_compare_func cmp_func)
Create an empty tree that orders keys with |cmp_func| (must not be NULL).
Definition pr_tree.c:110
size_t pr_tree_max_path_length(const pr_tree *tree)
Return the greatest depth of any node, the root being at depth 1, or 0 for an empty tree: the height ...
Definition pr_tree.c:389
dict * pr_dict_new(dict_compare_func cmp_func)
Like pr_tree_new(), but wrapped in a generic dict for use with the dict_* macros.
Definition pr_tree.c:125
void ** pr_tree_search_gt(pr_tree *tree, const void *key)
Return the address of the datum of the least key greater than |key|, or NULL if there is none.
Definition pr_tree.c:143
void ** pr_tree_search_lt(pr_tree *tree, const void *key)
Return the address of the datum of the greatest key less than |key|, or NULL if there is none.
Definition pr_tree.c:141
const void * pr_itor_key(const pr_itor *itor)
Return the key |itor| is positioned on, or NULL if it is not positioned.
Definition pr_tree.c:549
bool pr_itor_next(pr_itor *itor)
Move |itor| to the next element in key order and return true, or unposition it and return false if th...
Definition pr_tree.c:538
dict_itor * pr_dict_itor_new(pr_tree *tree)
Like pr_itor_new(), but wrapped in a generic dict_itor for use with the dict_itor_* macros.
Definition pr_tree.c:522
dict_insert_result pr_tree_insert(pr_tree *tree, void *key)
Insert |key| unless an equal key is present.
Definition pr_tree.c:265
size_t pr_tree_traverse(pr_tree *tree, dict_visit_func visit, void *user_data)
Call |visit|(key, datum, |user_data|) for each element in key order, stopping early if |visit| return...
Definition pr_tree.c:354
bool pr_itor_prevn(pr_itor *itor, size_t count)
Move |itor| |count| elements back and return whether it is still positioned.
Definition pr_tree.c:541
bool pr_itor_remove(pr_itor *it)
Remove the element |itor| is positioned on and unposition |itor|; return false if it was not position...
Definition pr_tree.c:554
bool pr_itor_nextn(pr_itor *itor, size_t count)
Move |itor| |count| elements forward and return whether it is still positioned.
Definition pr_tree.c:540
dict_remove_result pr_tree_remove(pr_tree *tree, const void *key)
Remove the element with key |key|.
Definition pr_tree.c:341
void pr_itor_free(pr_itor *itor)
Free an iterator.
Definition pr_tree.c:535
bool pr_itor_valid(const pr_itor *itor)
Return whether |itor| is positioned on an element.
Definition pr_tree.c:536
void ** pr_tree_search_ge(pr_tree *tree, const void *key)
Return the address of the datum of the least key greater than or equal to |key|, or NULL if there is ...
Definition pr_tree.c:142
int pr_itor_compare(const pr_itor *i1, const pr_itor *i2)
Compare the positions of two iterators over the same tree: return a negative value,...
Definition pr_tree.c:551
bool pr_itor_prev(pr_itor *itor)
Move |itor| to the previous element in key order and return true, or unposition it and return false i...
Definition pr_tree.c:539
bool pr_tree_select(pr_tree *tree, size_t n, const void **key, void **datum)
Store the key and datum of the |n|th element in key order (0-based) through |key| and |datum| and ret...
Definition pr_tree.c:360
size_t pr_tree_min_path_length(const pr_tree *tree)
Return the shallowest depth at which a child link is absent, the root being at depth 1,...
Definition pr_tree.c:390
bool pr_itor_last(pr_itor *itor)
Position |itor| on the last element in key order and return true, or unposition it and return false i...
Definition pr_tree.c:543
size_t pr_tree_clear(pr_tree *tree, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL.
Definition pr_tree.c:351
bool pr_itor_search_le(pr_itor *itor, const void *key)
Position |itor| on the greatest key less than or equal to |key| and return true, or unposition it and...
Definition pr_tree.c:545
bool pr_itor_search_ge(pr_itor *itor, const void *key)
Position |itor| on the least key greater than or equal to |key| and return true, or unposition it and...
Definition pr_tree.c:547
size_t pr_tree_free(pr_tree *tree, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL,...
Definition pr_tree.c:138
bool pr_itor_search(pr_itor *itor, const void *key)
Position |itor| on |key| and return true, or unposition it and return false if |key| is not present.
Definition pr_tree.c:544
bool pr_itor_first(pr_itor *itor)
Position |itor| on the first element in key order and return true, or unposition it and return false ...
Definition pr_tree.c:542
#define WEIGHT(n)
Definition pr_tree.c:43
void ** pr_tree_search_le(pr_tree *tree, const void *key)
Return the address of the datum of the greatest key less than or equal to |key|, or NULL if there is ...
Definition pr_tree.c:140
void ** pr_itor_datum(pr_itor *itor)
Return the address of the datum |itor| is positioned on, through which it can be read or replaced,...
Definition pr_tree.c:550
size_t pr_tree_total_path_length(const pr_tree *tree)
Return the sum of the depths of all nodes, the root being at depth 1, or 0 for an empty tree.
Definition pr_tree.c:391
size_t pr_tree_count(const pr_tree *tree)
Return the number of elements.
Definition pr_tree.c:388
bool pr_tree_verify(const pr_tree *tree)
Check the internal invariants of the tree and return true if they hold, or print the first failed che...
Definition pr_tree.c:496
pr_itor * pr_itor_new(pr_tree *tree)
Create an iterator over |tree| that is not positioned on any element yet.
Definition pr_tree.c:511
void pr_itor_invalidate(pr_itor *itor)
Unposition |itor|, so that it is not positioned on any element.
Definition pr_tree.c:537
void ** pr_tree_search(pr_tree *tree, const void *key)
Return the address of the datum stored for |key|, or NULL if |key| is not present.
Definition pr_tree.c:139
bool pr_itor_search_gt(pr_itor *itor, const void *key)
Position |itor| on the least key greater than |key| and return true, or unposition it and return fals...
Definition pr_tree.c:548
bool pr_itor_search_lt(pr_itor *itor, const void *key)
Position |itor| on the greatest key less than |key| and return true, or unposition it and return fals...
Definition pr_tree.c:546
Path-reduction tree [Gonnet 1983].
void * _itor
Definition dict.h:235
const itor_vtable * _vtable
Definition dict.h:236
The operations of one container type.
Definition dict.h:110
Definition dict.h:164
void * _object
Definition dict.h:165
const dict_vtable * _vtable
Definition dict.h:166
pr_tree * tree
Definition pr_tree.c:50
pr_node * node
Definition pr_tree.c:50
pr_node * llink
Definition pr_tree.c:39
void * datum
Definition pr_tree.c:39
unsigned weight
Definition pr_tree.c:40
pr_node * rlink
Definition pr_tree.c:39
void * key
Definition pr_tree.c:39
pr_node * parent
Definition pr_tree.c:39
dict_compare_func cmp_func
Definition tree_common.c:38
tree_node * root
Definition tree_common.c:38
size_t count
Definition tree_common.c:38
size_t rotation_count
Definition tree_common.c:38
bool tree_iterator_last(void *Iterator)
size_t tree_free(void *Tree, dict_delete_func delete_func)
void ** tree_iterator_datum(void *Iterator)
bool tree_iterator_next(void *Iterator)
void * tree_node_max(void *Node)
void tree_iterator_invalidate(void *Iterator)
void ** tree_search_gt(void *Tree, const void *key)
int tree_iterator_compare(const void *Iterator1, const void *Iterator2)
void tree_node_rot_left(void *Tree, void *Node)
Definition tree_common.c:46
void * tree_search_node(void *Tree, const void *key)
bool tree_iterator_search_le(void *Iterator, const void *key)
bool tree_iterator_valid(const void *Iterator)
size_t tree_count(const void *Tree)
void ** tree_search_lt(void *Tree, const void *key)
size_t tree_clear(void *Tree, dict_delete_func delete_func)
const void * tree_iterator_key(const void *Iterator)
size_t tree_min_path_length(const void *Tree)
void * tree_node_min(void *Node)
void ** tree_search(void *Tree, const void *key)
bool tree_iterator_nextn(void *Iterator, size_t count)
size_t tree_traverse(void *Tree, dict_visit_func visit, void *user_data)
size_t tree_total_path_length(const void *Tree)
bool tree_iterator_first(void *Iterator)
void tree_iterator_free(void *Iterator)
bool tree_iterator_prevn(void *Iterator, size_t count)
bool tree_iterator_search_lt(void *Iterator, const void *key)
bool tree_iterator_search_ge(void *Iterator, const void *key)
size_t tree_max_path_length(const void *Tree)
void * tree_iterator_key_vt(void *Iterator)
int tree_iterator_compare_vt(void *Iterator1, void *Iterator2)
bool tree_iterator_search_gt(void *Iterator, const void *key)
void ** tree_search_ge(void *Tree, const void *key)
void tree_node_rot_right(void *Tree, void *Node)
Definition tree_common.c:62
void ** tree_search_le(void *Tree, const void *key)
bool tree_iterator_search(void *Iterator, const void *key)
bool tree_iterator_prev(void *Iterator)
#define TREE_NODE_FIELDS(node_type)
Definition tree_common.h:33
#define TREE_ITERATOR_FIELDS(tree_type, node_type)
Definition tree_common.h:54
#define TREE_FIELDS(node_type)
Definition tree_common.h:44