1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | #include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include "avl.h"
/********************************************************************
|* AVL Tree
\*/
int main(int argc, char* argv[]) {
BSTNode* root = NULL;
insert(4, &root);
insert(2, &root);
insert(6, &root);
insert(1, &root);
insert(3, &root);
insert(5, &root);
insert(7, &root);
print_bst(root, "Inserted as 4 2 6 1 3 5 7: ");
printf("Height: %d\n", get_height(root));
printf("Height: %d\n", get_height_without_using_field(root));
assert(is_every_node_in_tree_avl_balanced(root));
free_tree(&root);
insert(1, &root);
insert(2, &root);
insert(3, &root);
insert(4, &root);
insert(5, &root);
insert(6, &root);
insert(7, &root);
print_bst(root, "Inserted as 1 2 3 4 5 6 7: ");
printf("Height: %d\n", get_height(root));
printf("Height: %d\n", get_height_without_using_field(root));
assert(is_every_node_in_tree_avl_balanced(root));
free_tree(&root);
insert(7, &root);
insert(6, &root);
insert(5, &root);
insert(4, &root);
insert(3, &root);
insert(2, &root);
insert(1, &root);
print_bst(root, "Inserted as 7 6 5 4 3 2 1: ");
printf("Height: %d\n", get_height(root));
printf("Height: %d\n", get_height_without_using_field(root));
assert(is_every_node_in_tree_avl_balanced(root));
free_tree(&root);
return EXIT_SUCCESS;
}
/////////////////////////////////////////////////////////////////////
// BASIC BST OPERATIONS
//
void insert(int value, BSTNode** a_root) {
if(*a_root == NULL) {
*a_root = malloc(sizeof **a_root);
**a_root = (BSTNode) { .value = value, .left = NULL, .right = NULL, .height = 0 };
}
else if(value < (*a_root) -> value) {
insert(value, &((*a_root) -> left));
update_height(*a_root);
balance_after_insert_in_left(value, a_root);
}
else if(value > (*a_root) -> value) {
insert(value, &((*a_root) -> right));
update_height(*a_root);
balance_after_insert_in_right(value, a_root);
}
}
void free_tree(BSTNode** a_root) {
if(*a_root != NULL) {
free_tree(&((*a_root) -> left));
free_tree(&((*a_root) -> right));
free(*a_root);
*a_root = NULL;
}
}
/////////////////////////////////////////////////////////////////////
// AVL ROTATIONS
//
void rotate_counterclockwise(BSTNode** a_root) { // Rotate right with root
BSTNode* old_root = *a_root;
BSTNode* new_root = old_root -> right;
old_root -> right = new_root -> left; // old_root -> right := "b"
new_root -> left = old_root;
*a_root = new_root;
update_height(old_root);
update_height(new_root);
}
void rotate_clockwise(BSTNode** a_root) { // Rotate left with root
BSTNode* old_root = *a_root;
BSTNode* new_root = old_root -> left;
old_root -> left = new_root -> right; // old_root -> left := "b"
new_root -> right = old_root;
*a_root = new_root;
update_height(old_root);
update_height(new_root);
}
void balance_after_insert_in_left(int value, BSTNode** a_root) {
if(get_balance_score(*a_root) == 2) {
if(value < (*a_root) -> left -> value) {
// Single rotation -- after insert in root -> left -> left
rotate_clockwise(a_root);
}
else {
// Double rotation -- after insert in root -> left -> right
rotate_counterclockwise(&((*a_root) -> left));
rotate_clockwise(a_root);
}
}
}
void balance_after_insert_in_right(int value, BSTNode** a_root) {
if(get_balance_score(*a_root) == -2) {
if(value > (*a_root) -> right -> value) {
// Single rotation -- after insert in root -> right -> right
rotate_counterclockwise(a_root);
}
else {
// Double rotation -- after insert in root -> right -> left
rotate_clockwise(&((*a_root) -> right));
rotate_counterclockwise(a_root);
}
}
}
/////////////////////////////////////////////////////////////////////
// METRICS (height and balance)
//
int get_balance_score(BSTNode const* root) {
return get_height(root -> left) - get_height(root -> right);
}
void update_height(BSTNode* root) {
int height_of_left = get_height(root -> left);
int height_of_right = get_height(root -> right);
root -> height = 1 + (height_of_left > height_of_right ? height_of_left : height_of_right);
}
int get_height(BSTNode const* root) {
return root == NULL ? -1 : root -> height;
}
int get_height_without_using_field(BSTNode* root) {
if(root == NULL) {
return -1;
}
int height_of_left = get_height_without_using_field(root -> left);
int height_of_right = get_height_without_using_field(root -> right);
return 1 + (height_of_left < height_of_right ? height_of_left : height_of_right);
}
/////////////////////////////////////////////////////////////////////
// TESTING UTILITIES
//
void print_bst_nodes(BSTNode const* root) {
if(root != NULL) {
print_bst_nodes(root -> left);
printf("[%d] ", root -> value);
print_bst_nodes(root -> right);
}
}
bool is_every_node_in_tree_avl_balanced(BSTNode const* root) { // for testing
if(root != NULL) {
int balance_score = get_balance_score(root);
return balance_score >= -1 && balance_score <= 1
&& is_every_node_in_tree_avl_balanced(root -> left)
&& is_every_node_in_tree_avl_balanced(root -> right);
}
else {
return true;
}
}
void print_bst(BSTNode const* root, char const* label) {
printf("%s", label);
print_bst_nodes(root);
printf("\n");
}
/* vim: set tabstop=4 shiftwidth=4 fileencoding=utf-8 noexpandtab: */
|
© Copyright 2023 Alexander J. Quinn This content is protected and may not be shared, uploaded, or distributed.