| Current Path : /home/mudbot/gseen/ |
| Current File : //home/mudbot/gseen/generic_binary_tree.c |
/*
* Copyright (C) 2000,2001 Florian Sander
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define GENERIC_BINARY_TREE 1
struct generic_binary_tree {
void *root;
int (*comparedata) (void *data1, void *data2);
int (*expmemdata) (void *data);
void (*freedata) (void *data);
};
struct generic_binary_tree_node {
void *data;
void *left;
void *right;
};
static void btree_add(struct generic_binary_tree *, void *);
static int btree_expmem(struct generic_binary_tree *);
static int btree_recursive_expmem(struct generic_binary_tree *, struct generic_binary_tree_node *);
static void *btree_get(struct generic_binary_tree *, void *t);
static void btree_freetree(struct generic_binary_tree *);
static void btree_recursive_free(struct generic_binary_tree *,
struct generic_binary_tree_node *);
static void btree_getall(struct generic_binary_tree *, void (*) (void *));
static void btree_recursive_getall(struct generic_binary_tree_node *,
void (*) (void *));
static void btree_getall_expanded(struct generic_binary_tree *tree, void (*) (void *));
static void btree_recursive_getall_expanded(struct generic_binary_tree_node *,
void (*) (void *));
static void btree_remove(struct generic_binary_tree *, void *);
static void btree_add(struct generic_binary_tree *tree, void *data)
{
struct generic_binary_tree_node *node, *lastnode;
int cmp, lastcmp;
Assert(tree);
Assert(data);
cmp = lastcmp = 0;
node = tree->root;
lastnode = NULL;
while (node) {
cmp = tree->comparedata(node->data, data);
if (!cmp) {
// item is identical -> free old data and insert new
tree->freedata(node->data);
node->data = data;
return;
}
lastnode = node;
lastcmp = cmp;
if (cmp < 0)
node = node->left;
else
node = node->right;
}
node = nmalloc(sizeof(struct generic_binary_tree_node));
node->left = NULL;
node->right = NULL;
node->data = data;
if (!lastnode)
tree->root = node;
else {
Assert(lastcmp);
if (lastcmp < 0) {
Assert(!lastnode->left);
lastnode->left = node;
} else {
Assert(!lastnode->right);
lastnode->right = node;
}
}
}
static int btree_expmem(struct generic_binary_tree *tree)
{
int size = 0;
Assert(tree);
size += btree_recursive_expmem(tree, tree->root);
return size;
}
static int btree_recursive_expmem(struct generic_binary_tree *tree, struct generic_binary_tree_node *node)
{
int size = 0;
if (!node)
return 0;
size += sizeof(struct generic_binary_tree_node);
size += tree->expmemdata(node->data);
size += btree_recursive_expmem(tree, node->left);
size += btree_recursive_expmem(tree, node->right);
return size;
}
static void *btree_get(struct generic_binary_tree *tree, void *what)
{
struct generic_binary_tree_node *node;
int cmp;
node = tree->root;
while (node) {
cmp = tree->comparedata(node->data, what);
if (!cmp)
return node->data;
if (cmp < 0)
node = node->left;
else
node = node->right;
}
return NULL;
}
static void btree_freetree(struct generic_binary_tree *tree)
{
btree_recursive_free(tree, tree->root);
}
static void btree_recursive_free(struct generic_binary_tree *tree,
struct generic_binary_tree_node *node)
{
if (!node)
return;
btree_recursive_free(tree, node->left);
btree_recursive_free(tree, node->right);
tree->freedata(node->data);
nfree(node);
}
/* btree_getall():
* calls the specified function for each item in the tree.
* NOTE: getall() calls the proc _before_ it proceeds into recursion. This way,
* one can savely store the tree into a file without mixing up its form.
* But if you delete an item from the called prcedure, this function
* WILL crash. Use btree_getall() expanded instead.
*/
static void btree_getall(struct generic_binary_tree *tree, void (*func) (void *))
{
Assert(tree);
btree_recursive_getall(tree->root, func);
}
static void btree_recursive_getall(struct generic_binary_tree_node *node,
void (*func) (void *))
{
if (!node)
return;
// first call the function, then proceed into recursion
// this way, the tree keeps in form if its saved to a file, for example
Assert(func);
func(node->data);
btree_recursive_getall(node->left, func);
btree_recursive_getall(node->right, func);
}
/* btree_getall_expanded():
* the same as btree_getall(), but calls the function after the greatest level of recursion
* has been reached. The node-pointers won't be accessed anymore when the first function
* gets called. You can savely use this to free items.
*/
static void btree_getall_expanded(struct generic_binary_tree *tree, void (*func) (void *))
{
Assert(tree);
btree_recursive_getall_expanded(tree->root, func);
}
static void btree_recursive_getall_expanded(struct generic_binary_tree_node *node,
void (*func) (void *))
{
if (!node)
return;
btree_recursive_getall_expanded(node->left, func);
btree_recursive_getall_expanded(node->right, func);
Assert(func);
func(node->data);
}
static void btree_remove(struct generic_binary_tree *tree, void *data)
{
struct generic_binary_tree_node *node, *last, *largenode, *lastlarge;
int ret, lastret;
Assert(tree);
Assert(data);
last = NULL;
lastret = 0;
node = tree->root;
while (node) {
ret = tree->comparedata(node->data, data);
if (ret == 0)
break;
last = node;
lastret = ret;
if (ret < 0)
node = node->left;
else
node = node->right;
}
if (!node) // oops, item not found
return;
if (!node->left && !node->right) {
// *freu* no sub-branches! We can easily delete this item.
if (last) {
if (lastret < 0)
last->left = NULL;
else
last->right = NULL;
} else
tree->root = NULL;
} else if (!node->left) {
// also pretty easy. Just connect the child to the parent.
if (last) {
if (lastret < 0)
last->left = node->right;
else
last->right = node->right;
} else
tree->root = node->right;
} else if (!node->right) {
// same as above, but mirrored
if (last) {
if (lastret < 0)
last->left = node->left;
else
last->right = node->left;
} else
tree->root = node->left;
} else {
// aaargh... two sub-trees! The world is not fair... *sigh*
debug0("argl... worst case, two subtrees. :( Let's pray...");
// now we take the largest item from the left subtree and replace the
// doomed node with it.
// since it is the largest val, the tree remains valid and doesn't
// get deformed too much.
// at first, we have to find this node and cut it from the tree
largenode = node->left;
lastlarge = NULL;
while (largenode && largenode->right) {
lastlarge = largenode;
largenode = largenode->right;
}
// only set largenode->left to node->left if largenode exists.
// otherwise node->left points to largenode, which would result
// in a nice short-circuit
// If it does not exist, just leave largenode->left as it is because we just
// move largenode one level up, so it can keep its left subtree.
if (lastlarge) {
lastlarge->right = largenode->left;
largenode->left = node->left;
}
// now connect node's subtrees to it
largenode->right = node->right;
// and finally replace node with largenode
if (last) {
if (lastret < 0)
last->left = largenode;
else
last->right = largenode;
} else
tree->root = largenode;
}
// finally kill the node... we shouldn't need it anymore
tree->freedata(node->data);
nfree(node);
node = NULL;
}
#ifdef BTREE_WITHOPTIMIZE
static void btree_optimize(struct generic_binary_tree *tree,
struct generic_binary_tree_node *node,
struct generic_binary_tree_node *last,
int limit)
{
/* int leftdepth, rightdepth;
if (!node)
return;
btree_optimize(tree, node->left, node, last, limit);
btree_optimize(tree, node->right, node, last, limit);
leftdepth = btree_depth(node->left);
rightdepth = btree_depth(node->right);
if ((leftdepth - rightdepth) > limit) {
}
*/
}
#endif