tupperware: avl: add range mapping function

This commit is contained in:
Bruno BELANYI 2020-11-24 19:45:28 +01:00
parent 9e0706a7f3
commit 123ae1a347
2 changed files with 64 additions and 0 deletions

View file

@ -60,5 +60,7 @@ void avl_merge_all(struct avl *tree, struct avl *more);
void avl_prefix_map(struct avl *tree, avl_map_f map, void *cookie); void avl_prefix_map(struct avl *tree, avl_map_f map, void *cookie);
void avl_infix_map(struct avl *tree, avl_map_f map, void *cookie); void avl_infix_map(struct avl *tree, avl_map_f map, void *cookie);
void avl_postfix_map(struct avl *tree, avl_map_f map, void *cookie); void avl_postfix_map(struct avl *tree, avl_map_f map, void *cookie);
void avl_map_between(const struct avl *tree,
struct avl_node *inter[2], avl_map_f map, void *cookie);
#endif /* !TUPPERWARE_AVL_H */ #endif /* !TUPPERWARE_AVL_H */

View file

@ -522,3 +522,65 @@ struct between_parameters {
avl_map_f map; avl_map_f map;
void *cookie; void *cookie;
}; };
static bool map_between_helper(struct avl_node *cur,
const struct avl_node *end, avl_map_f map, void *cookie) {
if (!cur)
return false;
if (cur == end)
return true;
if (map_between_helper(cur->left, end, map, cookie))
return true;
map(cur, cookie);
return map_between_helper(cur->right, end, map, cookie);
}
static bool map_between_right(struct avl_node *cur,
const struct avl_node *end, avl_map_f map, void *cookie) {
if (!cur)
return false;
if (cur == end)
return true;
map(cur, cookie);
return map_between_helper(cur->right, end, map, cookie);
}
static struct avl_node *find_parent(const struct avl *tree,
struct avl_node *cur, const struct avl_node *v) {
struct avl_node *parent = NULL;
int c = 0;
while (cur && (c = tree->cmp(v, cur, tree->cookie))) {
parent = cur;
if (c < 0)
cur = cur->left;
else
cur = cur->right;
}
if (!cur)
return NULL;
if (cur == v)
return parent;
if (cur->left == v || cur->right == v)
return cur; // NOTE: needs better handling
if ((parent = find_parent(tree, cur->right, v)))
return parent;
if ((parent = find_parent(tree, cur->left, v)))
return parent;
return NULL;
}
void avl_map_between(const struct avl *tree,
struct avl_node *inter[2], avl_map_f map, void *cookie) {
if (!tree || !tree->root)
return;
struct avl_node *begin = inter[0];
const struct avl_node *end = inter[1];
// FIXME: finding the parent is inefficient
while (begin && !map_between_right(begin, end, map, cookie)) {
begin = find_parent(tree, tree->root, begin);
}
}