I am implementing an AVL tree in c but having some trouble with the balancing logic. Here is a portion of the code that shows the balancing logic:
struct Node{
void *data;
struct Node *left_node;
struct Node *right_node;
int height;
};
typedef struct Node Node;
struct AvlTree{
Node *root;
int (*comparator)(void*, void*);
char* (*to_string)(void*);
};
typedef struct AvlTree AvlTree;
void balance(Node *node){
int height_diff = get_height_difference(node);
Node *temp = node;
if(height_diff > 1){
Node *left = (node)->left_node;
if(get_height_difference(left) < 0){
temp = rotate_left(temp);
}
temp = rotate_right(temp);
}else if(height_diff < -1){
Node *right = (node)->right_node;
if(get_height_difference(right) > 0){
temp = rotate_right(temp);
}
temp = rotate_left(temp);
}
printf("%s %s\n", "Temp ", to_string_int(temp->data));
if(temp->left_node != NULL)printf("%s %s\n", "Left", to_string_int(temp->left_node->data));
if(temp->right_node != NULL)printf("%s %s\n", "Right", to_string_int(temp->right_node->data));
*node = *temp;
printf("%s %s\n", "Node ", to_string_int(node->data));
if(node->left_node != NULL)printf("%s %s\n", "Left", to_string_int(node->left_node->data));
if(node->right_node != NULL)printf("%s %s\n", "Right", to_string_int(node->right_node->data));
temp->height = get_node_height(temp);
}
Node *rotate_left(Node *node){
Node *right = node->right_node;
node->right_node = right->left_node;
right->left_node = node;
return right;
}
Node *rotate_right(Node *node){
Node *left = node->left_node;
node->left_node = left->right_node;
left->right_node = node;
return left;
}
In this code, in the method void balance(Node *node)
, after the line *node = *temp
, node and temp should point to the same Node. However printf shows different results for the node->left_node->data
and temp->left_node->data
;
Below is the full code for the avl tree:
#include<stdio.h>
#include<stdlib.h>
struct Node{
void *data;
struct Node *left_node;
struct Node *right_node;
int height;
};
typedef struct Node Node;
struct AvlTree{
Node *root;
int (*comparator)(void*, void*);
char* (*to_string)(void*);
};
typedef struct AvlTree AvlTree;
AvlTree *create_avl_tree(int (*)(void*, void*), char* (*)(void*));
void add_to_avl_tree(AvlTree*, void*);
void add(Node*, void*, int(*)(void*, void*));
void balance(Node*);
int get_node_height(Node*);
int get_height_difference(Node*);
Node *rotate_left(Node *node);
Node *rotate_right(Node *node);
char* to_string_int(void *data);
AvlTree *create_avl_tree(int (*comparator)(void*, void*), char* (*to_string)(void*)){
AvlTree *avl_tree = malloc(sizeof(AvlTree));
if(avl_tree == NULL){
puts("Out of Memory Exception");
exit(2);
}
avl_tree->root = NULL;
avl_tree->comparator = comparator;
avl_tree->to_string = to_string;
return avl_tree;
}
void add_to_avl_tree(AvlTree *avl_tree, void *data){
if(avl_tree == NULL){
puts("Null Pointer Exception");
exit(2);
}else{
if(avl_tree->root == NULL){
avl_tree->root = malloc(sizeof(Node));
if(avl_tree->root == NULL){
puts("Out of Memory Exception");
exit(2);
}
avl_tree->root->data = data;
avl_tree->root->left_node = NULL;
avl_tree->root->right_node = NULL;
avl_tree->root->height = 0;
}else{
add(avl_tree->root, data, avl_tree->comparator);
}
}
}
void add(Node *node, void *data, int (*comparator)(void*, void*)){
int n = comparator(node->data, data);
if(n < 0){
if(node->left_node == NULL){
node->left_node = malloc(sizeof(Node));
if(node->left_node == NULL){
puts("Out of Memory Exception");
exit(2);
}
node->left_node->data = data;
node->left_node->left_node = NULL;
node->left_node->right_node = NULL;
node->left_node->height = 0;
}else{
add(node->left_node, data, comparator);
}
}
else if(n > 0){
if(node->right_node == NULL){
node->right_node = malloc(sizeof(Node));
if(node->right_node == NULL){
puts("Out of Memory Exception");
exit(2);
}
node->right_node->data = data;
node->right_node->left_node = NULL;
node->right_node->right_node = NULL;
node->right_node->height = 0;
}else{
add(node->right_node, data, comparator);
}
}
node->height = get_node_height(node);
if(abs(get_height_difference(node)) >= 2){
balance(node);
}
}
int get_node_height(Node *node){
int height_left = 0;
if(node->left_node != NULL)height_left = node->left_node->height + 1;
int height_right = 0;
if(node->right_node != NULL)height_right = node->right_node->height + 1;
int height = height_left > height_right ? height_left : height_right;
return height;
}
int get_height_difference(Node *node){
int height_left = 0;
if(node->left_node != NULL)height_left = node->left_node->height + 1;
int height_right = 0;
if(node->right_node != NULL)height_right = node->right_node->height + 1;
return height_left - height_right;
}
void balance(Node *node){
int height_diff = get_height_difference(node);
Node *temp = node;
if(height_diff > 1){
Node *left = node->left_node;
if(get_height_difference(left) < 0){
temp = rotate_left(temp);
}
temp = rotate_right(temp);
}else if(height_diff < -1){
Node *right = node->right_node;
if(get_height_difference(right) > 0){
temp = rotate_right(temp);
}
temp = rotate_left(temp);
}
printf("%s %s\n", "Temp ", to_string_int(temp->data));
if(temp->left_node != NULL)printf("%s %s\n", "Left", to_string_int(temp->left_node->data));
if(temp->right_node != NULL)printf("%s %s\n", "Right", to_string_int(temp->right_node->data));
*node = *temp;
printf("%s %s\n", "Node ", to_string_int(node->data));
if(node->left_node != NULL)printf("%s %s\n", "Left", to_string_int(node->left_node->data));
if(node->right_node != NULL)printf("%s %s\n", "Right", to_string_int(node->right_node->data));
temp->height = get_node_height(temp);
}
Node *rotate_left(Node *node){
Node *right = node->right_node;
node->right_node = right->left_node;
right->left_node = node;
return right;
}
Node *rotate_right(Node *node){
Node *left = node->left_node;
node->left_node = left->right_node;
left->right_node = node;
return left;
}
int int_comp(void *s, void *t){
return *(int*)t - *(int*)s;
}
char* to_string_int(void *data){
char *c = malloc(sizeof(char) * 2);
*c = *(int*)data + '0';
*(c + 1) = 0;
return c;
}
int main(){
AvlTree *avl_tree = create_avl_tree(int_comp, to_string_int);
int a[] = {1,2,3};
for(int i =0; i < 3; i++){
add_to_avl_tree(avl_tree, &a[i]);
}
}
The output shows:
Temp 2
Left 1
Right 3
Node 2
Left 2
Right 3
The printf statements inside the void balance(Node *node)
is for testing purposes. I was trying to print the whole tree using the code below, but it would create an infinite loop and print the same number again and again, due to what seemed like circular dependency between the nodes(It would print 2 continuously).
void print_tree(AvlTree *avl_tree){
if(avl_tree != NULL){
print(avl_tree->root, avl_tree->to_string);
}
}
static void print(Node *node, char* (*to_string)(void*)){
/*Print the tree in this format
Node
Left Node
Left Node
Right Node
Right Node
Left Node
Right Node
*/
static int width = 0;
printf("%*s\n", width, to_string(node->data));
int next_width = 0;
if(node->left_node != NULL){
next_width = strlen(to_string(node->left_node->data));
}
if(node->right_node != NULL){
int temp_width = strlen(to_string(node->right_node->data));
if(next_width < temp_width)next_width = temp_width;
}
if(node->left_node == NULL && node->right_node == NULL){
next_width = 1;
}
next_width += width == 0 ? strlen(node->data) : 0;
width += next_width;
if(node->left_node != NULL)print(node->left_node, to_string);
else printf("%*s\n", width, ".");
if(node->right_node != NULL)print(node->right_node, to_string);
else printf("%*s\n", width, ".");
width -= next_width;
}