Untitled
unknown
plain_text
3 years ago
6.9 kB
15
Indexable
/**
* SD, 2023
*
* Lab 09 - BST & Heap
*
* Binary Search Tree implementation
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#define DIE(assertion, call_description) \
do { \
if (assertion) { \
fprintf(stderr, "(%s, %d): ", \
__FILE__, __LINE__); \
perror(call_description); \
exit(errno); \
} \
} while (0)
typedef struct bst_node_t bst_node_t;
struct bst_node_t {
/* left child */
bst_node_t *left;
/* right child */
bst_node_t *right;
/* data contained by the node */
void *data;
};
typedef struct bst_tree_t bst_tree_t;
struct bst_tree_t {
/* root of the tree */
bst_node_t *root;
/* size of the data contained by the nodes */
size_t data_size;
/* function used for sorting the keys */
int (*cmp)(const void *key1, const void *key2);
};
/**
* Helper function to create a node
* @data: the data to be added in the node
* @data_size: data's size
*/
static bst_node_t *__bst_node_create(void *data, size_t data_size)
{
bst_node_t *bst_node;
bst_node = malloc(sizeof(*bst_node));
DIE(bst_node == NULL, "bst_node malloc");
bst_node->left = bst_node->right = NULL;
bst_node->data = malloc(data_size);
DIE(bst_node->data == NULL, "bst_node->data malloc");
memcpy(bst_node->data, data, data_size);
return bst_node;
}
bst_tree_t *bst_tree_create(size_t data_size,
int (*cmp_f)(const void *, const void *))
{
bst_tree_t *bst_tree;
bst_tree = malloc(sizeof(*bst_tree));
DIE(bst_tree == NULL, "bst_tree malloc");
bst_tree->root = NULL;
bst_tree->data_size = data_size;
bst_tree->cmp = cmp_f;
return bst_tree;
}
void bst_tree_insert(bst_tree_t *bst_tree, void *data)
{
int rc;
bst_node_t *root = bst_tree->root;
bst_node_t *parent = root;
bst_node_t *node = __bst_node_create(data, bst_tree->data_size);
if (!parent) {
bst_tree->root = node;
return;
}
while (1) {
rc = bst_tree->cmp(parent->data, data);
if (rc < 0) {
if (parent->right == NULL) {
parent->right = node;
break;
}
parent = parent->right;
continue;
}
if (rc > 0) {
if (parent->left == NULL) {
parent->left = node;
break;
}
parent = parent->left;
continue;
}
if (rc == 0) {
free(node->data);
free(node);
break;
}
}
}
/**
* Helper function to remove an element from a BST
* @bst_node: the binary search subtree's root where to remove the element from
* @data: the data that is contained by the node which has to be removed
* @data_size: data size
* @cmp: function used to compare the data contained by two nodes
*/
static bst_node_t *__bst_tree_remove(bst_node_t *bst_node,
void *data, size_t data_size,
int (*cmp)(const void *, const void *))
{
int rc, rc_left, rc_right;
bst_node_t *max_left, *min_right;
if (!bst_node)
return NULL;
rc = cmp(data, bst_node->data);
if (rc < 0) {
bst_node->left = __bst_tree_remove(bst_node->left, data, data_size, cmp);
} else if (rc > 0) {
/* TODO */
bst_node->right = __bst_tree_remove(bst_node->right, data, data_size, cmp);
} else {
/* TODO */
if (!bst_node->right && !bst_node->left) {
free(bst_node->data);
free(bst_node);
return NULL;
} else if (!bst_node->right) {
bst_node_t *tmp = bst_node;
bst_node = bst_node->left;
free(tmp->data);
free(tmp);
} else if (!bst_node->left) {
bst_node_t *tmp = bst_node;
bst_node = bst_node->right;
free(tmp->data);
free(tmp);
} else {
min_right = bst_node->right;
max_left = bst_node->left;
while (max_left->right)
max_left = max_left->right;
while (min_right->left)
min_right = min_right->left;
rc_left = cmp(bst_node->data, max_left->data);
rc_right = cmp(min_right->data, bst_node->data);
if (rc_left < rc_right) {
memcpy(bst_node->data, max_left->data, data_size);
bst_node->left = __bst_tree_remove(bst_node->left, bst_node->data, data_size, cmp);
} else {
memcpy(bst_node->data, min_right->data, data_size);
bst_node->right = __bst_tree_remove(bst_node->right, bst_node->data, data_size, cmp);
}
}
}
return bst_node;
}
void bst_tree_remove(bst_tree_t *bst_tree, void *data)
{
bst_tree->root = __bst_tree_remove(bst_tree->root, data,
bst_tree->data_size, bst_tree->cmp);
}
/**
* Free the left and the right subtree of a node, its data and itself
* @b_node: the node which has to free its children and itself
* @free_data: function used to free the data contained by a node
*/
static void __bst_tree_free(bst_node_t *bst_node, void (*free_data)(void *))
{
if (!bst_node)
return;
__bst_tree_free(bst_node->left, free_data);
__bst_tree_free(bst_node->right, free_data);
free_data(bst_node);
}
void bst_tree_free(bst_tree_t *bst_tree, void (*free_data)(void *))
{
__bst_tree_free(bst_tree->root, free_data);
free(bst_tree);
}
static void
__bst_tree_print_inorder(bst_node_t* bst_node, void (*print_data)(void*))
{
if (!bst_node)
return;
__bst_tree_print_inorder(bst_node->left, print_data);
print_data(bst_node->data);
__bst_tree_print_inorder(bst_node->right, print_data);
}
void
bst_tree_print_inorder(bst_tree_t* bst_tree, void (*print_data)(void*))
{
__bst_tree_print_inorder(bst_tree->root, print_data);
}
/* --- TEST CODE BEGINS HERE --- */
/* don't change this */
#define MAX_STRING_SIZE 49
char to_lower(char c)
{
if ('A' <= c && c <= 'Z')
return c + 0x20;
return c;
}
int bst_cmp_str_lexicographically(const void *key1, const void *key2)
{
int rc, i, len;
char *str1 = (char *)key1;
char *str2 = (char *)key2;
int len1 = strlen(str1);
int len2 = strlen(str2);
len = len1 < len2 ? len1 : len2;
for (i = 0; i < len; ++i) {
rc = to_lower(str1[i]) - to_lower(str2[i]);
if (rc == 0)
continue;
return rc;
}
rc = to_lower(str1[i]) - to_lower(str2[i]);
return rc;
}
void print_data(void *data)
{
printf("%s\n", (char*)data);
}
int main(void)
{
bst_tree_t *bst;
int N = 0, task;
char str[BUFSIZ];
char buf[256];
fgets(buf, 256, stdin);
sscanf(buf, "%d\n", &N);
fflush(stdout);
bst = bst_tree_create(MAX_STRING_SIZE, bst_cmp_str_lexicographically);
while (N--) {
fgets(buf, 256, stdin);
sscanf(buf, "%d", &task);
memset(str, 0, BUFSIZ);
switch (task) {
case 1:
sscanf(buf + 2, "%s\n", str);
bst_tree_insert(bst, str);
break;
case 2:
sscanf(buf + 2, "%s\n", str);
bst_tree_remove(bst, str);
break;
case 3:
bst_tree_print_inorder(bst, print_data);
break;
default:
perror("Invalid task!");
}
}
bst_tree_free(bst, free);
return 0;
}
Editor is loading...