#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tree_node AVL_tree_node;
typedef struct tree_data
{
unsigned char value;
char* text;
}AVL_tree_data;
typedef struct tree_key
{
unsigned int address;
}AVL_tree_key;
struct tree_node
{
AVL_tree_node* left;
AVL_tree_node* right;
int depth_left;
int depth_right;
AVL_tree_key key;
AVL_tree_data data;
};
typedef struct
{
AVL_tree_node* root;
}AVL_tree;
typedef enum
{
AVL_ROT_NONE,
AVL_ROT_RIGHT,
AVL_ROT_LEFT,
AVL_ROT_RIGHT_LEFT,
AVL_ROT_LEFT_RIGHT
} AVL_tree_rotation;
/* initialize tree structure */
void AVL_init(AVL_tree* tree);
/* destroys tree structure */
void AVL_free(AVL_tree* tree);
/* adds node into the tree (only if tree with same address does not exist) */
void AVL_add(AVL_tree* tree, AVL_tree_key key, AVL_tree_data inputData);
/* find node in tree with given address */
AVL_tree_node* AVL_find(AVL_tree* tree, AVL_tree_key key);
/* prints tree */
void AVL_printTree(AVL_tree* tree);
/* prints node */
void AVL_printNode(AVL_tree_node* node, int spaces);
/* prints data of node */
void AVL_printNodeData(AVL_tree_key key, AVL_tree_data data);
static void AVL_nodeInit(AVL_tree_node* node);
static void AVL_nodeFree(AVL_tree_node* node);
static AVL_tree_rotation AVL_nodeAdd(AVL_tree_node** node, AVL_tree_key key, AVL_tree_data data);
static AVL_tree_node* AVL_findNode(AVL_tree_node* node, AVL_tree_key key);
static AVL_tree_rotation AVL_checkIfParentRotates(AVL_tree_node* node);
static void AVL_rotate(AVL_tree_node* node, AVL_tree_rotation type, char rotateLeftChild);
static void AVL_rotateLeft(AVL_tree_node* node, char rotateLeftChild);
static void AVL_rotateRight(AVL_tree_node* node, char rotateLeftChild);
static void AVL_nodeCopyKey(AVL_tree_key source, AVL_tree_key* destination);
static void AVL_nodeCopyData(AVL_tree_data source, AVL_tree_data* destination);
static void AVL_nodeFreeKey(AVL_tree_key key);
static void AVL_nodeFreeData(AVL_tree_data data);
static char compareNodes(AVL_tree_key a, AVL_tree_key b);
void AVL_init(AVL_tree* const tree)
{
tree->root = NULL;
}
void AVL_free(AVL_tree* const tree)
{
if(tree->root != NULL)
{
if(tree->root->left != NULL)
{
AVL_nodeFree(tree->root->left);
}
if(tree->root->right != NULL)
{
AVL_nodeFree(tree->root->right);
}
AVL_nodeFreeKey(tree->root->key);
AVL_nodeFreeData(tree->root->data);
tree->root = NULL;
}
}
void AVL_add(AVL_tree* tree, AVL_tree_key key, AVL_tree_data inputData)
{
// AVL_tree_data inputData = {.address = address, .value = value};
AVL_tree_rotation rotation = AVL_nodeAdd(&(tree->root), key, inputData);
if(rotation != AVL_ROT_NONE)
{
AVL_tree_node
* tmp
= (AVL_tree_node
*) malloc (sizeof(AVL_tree_node
)); tmp->left = tree->root;
/* rotate left subtree */
AVL_rotate(tmp, rotation, 1);
/* in tmp->left is new root of the tree */
tree->root = tmp->left;
tmp->left = NULL;
}
}
AVL_tree_node* AVL_find(AVL_tree* tree, AVL_tree_key key)
{
return AVL_findNode(tree->root, key);
}
static void AVL_nodeInit(AVL_tree_node* node)
{
node->left = node->right = NULL;
}
static void AVL_nodeFree(AVL_tree_node* node)
{
if(node->left != NULL)
{
AVL_nodeFree(node->left);
}
if(node->right != NULL)
{
AVL_nodeFree(node->right);
}
AVL_nodeFreeKey(node->key);
AVL_nodeFreeData(node->data);
}
static AVL_tree_rotation AVL_nodeAdd(AVL_tree_node** node, AVL_tree_key key, AVL_tree_data data)
{
AVL_tree_rotation returnRot = AVL_ROT_NONE;
/* if *node is NULL, create new node */
if((*node) == NULL)
{
*node
= (AVL_tree_node
*) malloc (sizeof(AVL_tree_node
));
AVL_nodeInit((*node));
AVL_nodeCopyData(data, &((*node)->data));
AVL_nodeCopyKey(key, &((*node)->key));
(*node)->depth_left = (*node)->depth_right = 0;
}
/*else find if new node should be created in left or right subtree */
else
{
char ret = 0;
char rotateLeftChild = 0;
AVL_tree_node* left, *right;
ret = compareNodes(key, (*node)->key);
/* if new node is considered less than actual node, work in left subtree */
if(ret == -1)
{
/* add node in left subtree
* returns type of rotation needed
*/
returnRot = AVL_nodeAdd(&((*node)->left), key, data);
left = (*node)->left;
/* flag indicating that left subtree will be rotated (if needed) */
rotateLeftChild = 1;
/* updated depth of left subtree */
(*node)->depth_left = 1 + (((left->depth_right) > (left->depth_left)) ? left->depth_right : left->depth_left);
}
/* if new node is considered more than actual node, work in right subtree */
else if(ret == 1)
{
/* add node in left subtree
* returns type of rotation needed
*/
returnRot = AVL_nodeAdd(&((*node)->right), key, data);
right = (*node)->right;
/* updated depth of right subtree */
(*node)->depth_right = 1 + (((right->depth_right) > (right->depth_left)) ? right->depth_right : right->depth_left);
}
/* check if rotation is supposed to happen */
if(returnRot != AVL_ROT_NONE)
{
AVL_rotate(*node, returnRot, rotateLeftChild);
}
/* calculate if parent should rotate */
returnRot = AVL_checkIfParentRotates(*node);
}
return returnRot;
}
static AVL_tree_rotation AVL_checkIfParentRotates(AVL_tree_node* node)
{
int depthDiff = 0, depthDiffChild = 0;
AVL_tree_rotation returnRot = AVL_ROT_NONE;
depthDiff = node->depth_left - node->depth_right;
/* if depth of left subtree is higher than depth of right subtree by more than 1, right rotation is needed */
if(depthDiff > 1)
{
depthDiffChild = node->left->depth_left - node->left->depth_right;
/* if depth of child's left subtree is higher than right subtree, only right rotation is needed */
if(depthDiffChild > 0)
{
returnRot = AVL_ROT_RIGHT;
}
/* if depth of child's left subtree is lower than right subtree, only left->right rotation is needed */
else if (depthDiffChild < 0)
{
returnRot = AVL_ROT_LEFT_RIGHT;
}
}
/* if depth of left subtree is less than depth of right subtree by more than 1, left rotation is needed */
else if(depthDiff < -1)
{
depthDiffChild = node->right->depth_left - node->right->depth_right;
/* if depth of child's left subtree is lower than right subtree, only left rotation is needed */
if(depthDiffChild < 0)
{
returnRot = AVL_ROT_LEFT;
}
/* if depth of child's left subtree is higher than right subtree, only right->left rotation is needed */
else if (depthDiffChild > 0)
{
returnRot = AVL_ROT_RIGHT_LEFT;
}
}
return returnRot;
}
static void AVL_rotate(AVL_tree_node* node, AVL_tree_rotation type, char rotateLeftChild)
{
char rotateLeftSubChild = 0;
AVL_tree_node* nodeToRotate = node->right;
if(rotateLeftChild == 1)
nodeToRotate = node->left;
if(nodeToRotate->depth_left - nodeToRotate->depth_right > 0)
rotateLeftSubChild = 1;
switch(type)
{
case AVL_ROT_LEFT:
// rotate to left
AVL_rotateLeft(node, rotateLeftChild);
break;
case AVL_ROT_RIGHT:
// rotate to right
AVL_rotateRight(node, rotateLeftChild);
break;
case AVL_ROT_LEFT_RIGHT:
// rotate child to left
AVL_rotateLeft(nodeToRotate, rotateLeftSubChild);
// then rotate to right
AVL_rotateRight(node, rotateLeftChild);
break;
case AVL_ROT_RIGHT_LEFT:
// rotate child to right
AVL_rotateRight(nodeToRotate, rotateLeftSubChild);
// then rotate to left
AVL_rotateLeft(node, rotateLeftChild);
break;
default:
break;
}
}
static void AVL_rotateLeft(AVL_tree_node* node, char rotateLeftChild)
{
AVL_tree_node** newRoot;
AVL_tree_node* oldRoot;
int* newRootDepth;
/* set newRoot to actual root of rotated subtree */
newRoot = &(node->right);
newRootDepth = &(node->depth_right);
if(rotateLeftChild == 1)
{
newRoot = &(node->left);
newRootDepth = &(node->depth_left);
}
/* store aside actual root */
oldRoot = *newRoot;
/* new root will be right child of actual root */
*newRoot = (*newRoot)->right;
/* new root's left subtree will now be old root's right subtree */
oldRoot->right = (*newRoot)->left;
/* new roots left subtree is old root */
(*newRoot)->left = oldRoot;
/* depths of nodes has to be updated */
/* old roots right subtree was new roots left subtree */
oldRoot->depth_right = (*newRoot)->depth_left;
/* new roots left subtree was old root */
(*newRoot)->depth_left = oldRoot->depth_left + 1;
/*new depth of parent node is 1 + maximum of new roots left subtree depths and right subtree depth*/
(*newRootDepth) = 1 + (((*newRoot)->depth_left > (*newRoot)->depth_right) ? (*newRoot)->depth_left : (*newRoot)->depth_right);
}
static void AVL_rotateRight(AVL_tree_node* node, char rotateLeftChild)
{
AVL_tree_node** newRoot;
AVL_tree_node* oldRoot;
int* newRootDepth;
/* set newRoot to actual root of rotated subtree */
newRoot = &(node->right);
newRootDepth = &(node->depth_right);
if(rotateLeftChild == 1)
{
newRoot = &(node->left);
newRootDepth = &(node->depth_left);
}
/* store aside actual root */
oldRoot = *newRoot;
/* new root will be left child of actual root */
*newRoot = (*newRoot)->left;
/* new root's right subtree will now be old root's left subtree */
oldRoot->left = (*newRoot)->right;
/* new roots right subtree is old root */
(*newRoot)->right = oldRoot;
/* depths of nodes has to be updated */
/* old roots left subtree was new roots right subtree */
oldRoot->depth_left = (*newRoot)->depth_right;
/* new roots right subtree was old root */
(*newRoot)->depth_right = oldRoot->depth_right + 1;
/*new depth of parent node is 1 + maximum of new roots left subtree depths and right subtree depth*/
(*newRootDepth) = 1 + (((*newRoot)->depth_left > (*newRoot)->depth_right) ? (*newRoot)->depth_left : (*newRoot)->depth_right);
}
static AVL_tree_node* AVL_findNode(AVL_tree_node* node, AVL_tree_key key)
{
if(node == NULL)
return NULL;
if(compareNodes(node->key, key) == 0)
return node;
else if(node->left != NULL && compareNodes(node->key, key) == 1)
return AVL_findNode(node->left, key);
else if(node->right != NULL && compareNodes(node->key, key) == -1)
return AVL_findNode(node->right, key);
else
return NULL;
}
void AVL_printTree(AVL_tree* tree)
{
AVL_printNode(tree->root, 0);
}
void AVL_printNode(AVL_tree_node* node, int spaces)
{
const int spaceIndent = 10;
if(node == NULL)
return;
// print right
AVL_printNode(node->right, spaces + spaceIndent);
// print root
for(int i = 0; i < spaces; ++i)
printf("%d:%d:", node
->depth_right
, node
->depth_left
); AVL_printNodeData(node->key, node->data);
// print left
AVL_printNode(node->left, spaces + spaceIndent);
}
void AVL_printNodeData(AVL_tree_key key, AVL_tree_data data)
{
printf("(%d;%d;%s)\n", key.
address, data.
value, data.
text); }
static void AVL_nodeCopyKey(AVL_tree_key source, AVL_tree_key* destination)
{
// printf("%d <- %d\n", destination->address, source.address);
destination->address = source.address;
}
static void AVL_nodeCopyData(AVL_tree_data source, AVL_tree_data* destination)
{
int textLenCnt = 0;
char* txtIt = source.text;
while(*(txtIt++) != 0)
{
textLenCnt++;
}
destination
->text
= (char*) calloc (textLenCnt
+ 1, sizeof(char)); memcpy(destination
->text
, source.
text, textLenCnt
); //destination->text[0] ^= 0x20;
destination->value = source.value;
}
static void AVL_nodeFreeKey(AVL_tree_key key)
{
}
static void AVL_nodeFreeData(AVL_tree_data data)
{
}
static char compareNodes(AVL_tree_key a, AVL_tree_key b)
{
/* 1 means a is more than b */
if(a.address > b.address)
return 1;
/* -1 means a is less than b */
else if (a.address < b.address)
return -1;
/* 0 means a equals b */
else
return 0;
}
int main(void)
{
// learnMonths();
// learnConjugation();
AVL_tree tree;
AVL_tree_node* foundNode;
AVL_tree testLeft, testRight, testRL;
AVL_tree randomTree;
AVL_init(&tree);
AVL_init(&testLeft);
AVL_init(&testRight);
AVL_init(&testRL);
AVL_init(&randomTree);
char* dd
= (char*) malloc (5); dd[4] = 0;
// test of add functionality
AVL_add(&tree, (AVL_tree_key){10}, (AVL_tree_data){20, dd});
AVL_printTree(&tree);
printf("-----------------------------------------------------\n"); AVL_add(&tree, (AVL_tree_key){30}, (AVL_tree_data){40, "qwe"});
AVL_printTree(&tree);
printf("-----------------------------------------------------\n"); AVL_add(&tree, (AVL_tree_key){50}, (AVL_tree_data){80, "rty"});
AVL_printTree(&tree);
printf("-----------------------------------------------------\n"); AVL_add(&tree, (AVL_tree_key){20}, (AVL_tree_data){100, "fgh"});
AVL_printTree(&tree);
printf("-----------------------------------------------------\n"); AVL_add(&tree, (AVL_tree_key){84}, (AVL_tree_data){1, "zxc"});
AVL_printTree(&tree);
printf("-----------------------------------------------------\n"); AVL_add(&tree, (AVL_tree_key){12}, (AVL_tree_data){77, "vbn"});
AVL_printTree(&tree);
printf("-----------------------------------------------------\n");
dd[0] = 'Q';
// // test of find functionality
// foundNode = AVL_find(&tree, (AVL_tree_key){88});
// if(foundNode != NULL)
// AVL_printNodeData(foundNode->key, foundNode->data);
// else
// printf("NODE NOT FOUND\n");
//
// foundNode = AVL_find(&tree, (AVL_tree_key){84});
// if(foundNode != NULL)
// AVL_printNodeData(foundNode->key, foundNode->data);
// else
// printf("NODE NOT FOUND\n");
//
// foundNode = AVL_find(&tree, (AVL_tree_key){30});
// if(foundNode != NULL)
// AVL_printNodeData(foundNode->key, foundNode->data);
// else
// printf("NODE NOT FOUND\n");
// printf("-----------------------------------------------------\n");
//
// // change value of found address
// foundNode->data.text = "ppp";
// AVL_printTree(&tree);
// AVL_add(&testLeft, 10, 10);
// AVL_printTree(&testLeft);
// printf("-----------------------------------------------------\n");
// AVL_add(&testLeft, 20, 20);
// AVL_printTree(&testLeft);
// printf("-----------------------------------------------------\n");
// AVL_add(&testLeft, 30, 30);
// AVL_printTree(&testLeft);
// printf("-----------------------------------------------------\n");
// AVL_add(&testLeft, 40, 40);
// AVL_printTree(&testLeft);
// printf("-----------------------------------------------------\n");
// AVL_add(&testLeft, 50, 50);
// AVL_printTree(&testLeft);
// printf("-----------------------------------------------------\n");
// AVL_add(&testLeft, 60, 60);
// AVL_printTree(&testLeft);
// printf("-----------------------------------------------------\n");
// AVL_add(&testLeft, 70, 70);
// AVL_printTree(&testLeft);
// printf("-----------------------------------------------------\n");
// AVL_add(&testLeft, 80, 80);
// AVL_printTree(&testLeft);
// printf("-----------------------------------------------------\n");
//
// printf("-----------------------------------------\n");
//
// AVL_add(&testRight, 80, 80);
// AVL_printTree(&testRight);
// printf("-----------------------------------------------------\n");
// AVL_add(&testRight, 70, 70);
// AVL_printTree(&testRight);
// printf("-----------------------------------------------------\n");
// AVL_add(&testRight, 60, 60);
// AVL_printTree(&testRight);
// printf("-----------------------------------------------------\n");
// AVL_add(&testRight, 50, 50);
// AVL_printTree(&testRight);
// printf("-----------------------------------------------------\n");
// AVL_add(&testRight, 40, 40);
// AVL_printTree(&testRight);
// printf("-----------------------------------------------------\n");
// AVL_add(&testRight, 30, 30);
// AVL_printTree(&testRight);
// printf("-----------------------------------------------------\n");
// AVL_add(&testRight, 20, 20);
// AVL_printTree(&testRight);
// printf("-----------------------------------------------------\n");
// AVL_add(&testRight, 10, 10);
// AVL_printTree(&testRight);
// printf("-----------------------------------------------------\n");
//
// printf("-----------------------------------------\n");
//
// AVL_add(&testRL, 20, 20);
// AVL_printTree(&testRL);
// printf("-----------------------------------------\n");
// AVL_add(&testRL, 40, 40);
// AVL_printTree(&testRL);
// printf("-----------------------------------------\n");
// AVL_add(&testRL, 30, 30);
// AVL_printTree(&testRL);
// printf("-----------------------------------------\n");
// AVL_printTree(&testRL);
// printf("-----------------------------------------\n");
//
//// /* random adds into tree */
//// for(int i = 0; i < 10000; ++i)
//// {
//// AVL_add(&randomTree, rand()%(1<<20), i);
//// }
//// AVL_printTree(&randomTree);
//// printf("-----------------------------------------\n");
////
//// for(int j = 0; j < 20; ++j)
//// {
//// printf("%d. tree\n", j+1);
//// AVL_free(&randomTree);
//// for(int i = 0; i < 100000; ++i)
//// {
//// AVL_add(&randomTree, rand()%(1<<26), i);
//// }
//// }
// AVL_free(&tree);
// AVL_free(&tree);
// AVL_free(&testLeft);
// AVL_free(&testRight);
// AVL_free(&testRL);
// AVL_free(&randomTree);
// system("pause");
return 0;
}