radare2/libr/util/btree.c
2016-09-19 14:44:47 +02:00

209 lines
4.9 KiB
C

/* radare - LGPL - Copyright 2009-2015 - pancake */
#include <btree.h>
R_API void btree_init(struct btree_node **T) {
*T = NULL;
}
R_API struct btree_node *btree_remove(struct btree_node *p, BTREE_DEL(del)) {
struct btree_node *rp = NULL, *f;
if (!p) return p;
if (p->right) {
if (p->left) {
f = p;
rp = p->right;
while (rp->left) {
f = rp;
rp = rp->left;
}
if (f!=p) {
f->left = rp->right;
rp->right = p->right;
rp->left = p->left;
} else rp->left = p->left;
} else rp = p->right;
} else rp = p->left;
if (del) del (p->data);
free (p);
return(rp);
}
R_API void *btree_search(struct btree_node *root, void *x, BTREE_CMP(cmp), int parent) {
struct btree_node *p = NULL;
if (root) {
if (cmp (x, root->data)<0)
p = btree_search (root->left, x, cmp, parent);
else if (cmp(x, root->data)>0)
p = btree_search (root->right, x, cmp, parent);
else p = root;
}
/* node found */
if (p) {
if (parent)
return root;
return p;
} return NULL;
}
R_API void btree_traverse(struct btree_node *root, int reverse, void *context, BTREE_TRV(trv)) {
if (root) {
if (reverse) {
btree_traverse (root->right, reverse, context, trv);
trv(root->data, context);
btree_traverse (root->left, reverse, context, trv);
} else {
btree_traverse (root->left, reverse, context, trv);
trv(root->data, context);
btree_traverse (root->right, reverse, context, trv);
}
}
}
R_API bool btree_del(struct btree_node *proot, void *x, BTREE_CMP(cmp), BTREE_DEL(del)) {
struct btree_node *p = btree_search (proot, x, cmp, 1);
if (p) {
// p->right =
btree_remove (p->left, del);
p->left = NULL;
return true;
}
return false;
}
R_API void *btree_get(struct btree_node *proot, void *x, BTREE_CMP(cmp)) {
struct btree_node *p = btree_search (proot, x, cmp, 0);
if (p) {
p->hits++;
return p->data;
}
return NULL;
}
R_API void btree_cleartree(struct btree_node *proot, BTREE_DEL(del)) {
if (proot) {
btree_cleartree (proot->left, del);
btree_cleartree (proot->right, del);
if (del) del (proot->data);
free (proot);
}
}
R_API void btree_insert(struct btree_node **T, struct btree_node *p, BTREE_CMP(cmp)) {
int ret = cmp (p->data, (*T)->data);
if (ret<0) {
if ((*T)->left) btree_insert (&(*T)->left, p, cmp);
else (*T)->left = p;
} else if (ret>0) {
if ((*T)->right) btree_insert (&(*T)->right, p, cmp);
else (*T)->right = p;
}
}
R_API void btree_add(struct btree_node **T, void *e, BTREE_CMP(cmp)) {
struct btree_node *p = (struct btree_node*)
malloc(sizeof(struct btree_node));
p->data = e;
p->hits = 0;
p->left = p->right = NULL;
if (!*T) *T = p;
else btree_insert (T, p, cmp);
}
/* unused */
R_API int btree_empty(struct btree_node **T) {
return !( (T && (*T) && ((*T)->right || (*T)->left)) );
}
R_API struct btree_node *btree_hittest(struct btree_node *root, struct btree_node *hn) {
struct btree_node *p = root;
if (root) {
struct btree_node *ml = btree_hittest(root->left, root);
struct btree_node *mr = btree_hittest(root->right, root);
if (ml && ml->hits > p->hits) p = ml;
if (mr && mr->hits > p->hits) p = mr;
}
return p;
}
R_API int btree_optimize(struct btree_node **T, BTREE_CMP(cmp)) {
struct btree_node *node, *NT = NULL;
do {
node = btree_hittest (*T, NULL);
if (node) {
btree_add (&NT, node->data, cmp);
btree_del (*T, node->data, cmp, NULL);
}
} while (node);
*T = NT; /* replace one tree with the other */
return 0;
}
#if MAIN
struct mydata {
unsigned long long addr;
char *str;
};
int shownode(char *str, struct mydata *m) {
if (!m)
printf ("==> not found\n");
else printf ("==> %s: %s, %"PFMT64d"\n", str, m->str, m->addr);
return 0;
}
int mycmp(const void *a, const void *b) {
struct mydata *ma = (struct mydata *)a;
struct mydata *mb = (struct mydata *)b;
if (!a || !b) return 0;
return (int)(ma->addr-mb->addr);
}
int main() {
struct btree_node *n, *bt = NULL;
//btree_init(&bt);
struct mydata foo = { 10, "hello" };
struct mydata bar = { 20, "world" };
printf("EMPTY TREE: %d\n", btree_empty(&bt));
btree_add(&bt, &foo, mycmp);
btree_add(&bt, &bar, mycmp);
printf ("EMPTY TREE: %d\n", btree_empty(&bt));
printf("==== go search ====\n");
/* find existent data */
struct mydata *p = btree_get (bt, &bar, mycmp);
shownode("result for 20: ", p);
printf("==== go search ====\n");
/* find unexistent data */
struct mydata nop = { 15, NULL };
p = btree_get(bt, &nop, mycmp);
shownode("result for 15: ", p);
printf("==== go get hittest ====\n");
n = btree_hittest(bt, NULL);
shownode("hitest is: ", p);
printf("==== go remove 20 ====\n");
if (btree_del(bt, &bar, mycmp, NULL))
printf("node found and removed\n");
else printf("oops\n");
printf("==== go search ====\n");
/* find existent data */
p = btree_get(bt, &bar, mycmp);
shownode("result for 20: ", p);
printf("==== go search ====\n");
/* find existent data */
p = btree_get(bt, &foo, mycmp);
shownode("result for 10: ", p);
btree_cleartree(bt, NULL);
return 0;
}
#endif