ds/tree.h

144 lines
3.6 KiB
C

#ifndef TREE_H
#define TREE_H
#include <string.h>
#include <stdbool.h>
typedef struct tnode_ tnode_t;
typedef struct tnode_* tnode_ptr;
typedef enum { INT, UINT, CHAR, FLOAT, DOUBLE, CHAR_PTR, VOID_PTR } tnode_value_t;
typedef struct tnode_ {
int type;
union {
int vi;
unsigned int vui;
char vc;
float vf;
double vd;
char *vcp;
void *vptr;
};
tnode_ptr parent;
tnode_ptr left_child;
tnode_ptr right_child;
} tnode_t;
int compare(int type, void *left, void *right)
{
switch (type)
{
case INT:
return *((int*)left) - *((int*)right);
case UINT:
return *((unsigned int*)left) - *((unsigned int*)right);
case FLOAT:
return *((float*)left) - *((float*)right);
case DOUBLE:
return *((float*)left) - *((float*)right);
case CHAR_PTR:
return strcmp((char*)left, (char*)right);
default:
return 0;
}
}
tnode_t* btree_root(tnode_t *node)
{
tnode_t* current = node;
while((current = current->parent) && current->parent);
return current;
}
void btree_insert(tnode_t *root, tnode_t *new_node)
{
tnode_t *current = root;
int rootdiff = compare(current->type, &current->vi, &new_node->vi);
bool left = current->left_child != NULL;
bool right = current->right_child != NULL;
if (!rootdiff) return;
if (left)
{
if (rootdiff < 0)
btree_insert(current->left_child, new_node);
}
else
{
if (rootdiff < 0)
{
current->left_child = new_node;
new_node->parent = current;
}
}
if (right)
{
if (rootdiff > 0)
btree_insert(current->right_child, new_node);
}
else
{
if (rootdiff > 0)
{
current->right_child = new_node;
new_node->parent = current;
}
}
}
void btree_delete(tnode_t *root, void *data)
{
int rootdiff = compare(root->type, &root->vi, data);
bool left = root->left_child;
bool right = root->right_child;
tnode_t **position_in_parent_ptr = NULL;
if (root->parent && root->parent->left_child == root)
position_in_parent_ptr = &root->parent->left_child;
if (root->parent && root->parent->right_child == root)
position_in_parent_ptr = &root->parent->right_child;
if (rootdiff < 0 && left)
{
btree_delete(root->left_child, data);
}
if (rootdiff > 0 && right)
{
btree_delete(root->right_child, data);
}
if (!rootdiff)
{
if (left && !right)
{
root->left_child->parent = root->parent;
if (position_in_parent_ptr)
*position_in_parent_ptr = root->left_child;
}
if (!left && right)
{
root->right_child->parent = root->parent;
if (position_in_parent_ptr)
*position_in_parent_ptr = root->right_child;
}
if (left && right)
{
tnode_t *walker = root->right_child;
while (walker->left_child) walker = walker->left_child;
if (position_in_parent_ptr)
*position_in_parent_ptr = walker;
walker->parent = root->parent;
}
}
}
tnode_t* btree_find(tnode_t *current, void *data)
{
int currentdiff = compare(current->type, &current->vi, data);
if (!currentdiff) return current;
if (currentdiff < 0)
if (current->left_child) btree_find(current->left_child, data);
else return NULL;
else
if (current->right_child) btree_find(current->right_child, data);
else return NULL;
}
#endif //TREE_H