/* Copyright 2016 secXsQuared * Distributed under GPL license * See COPYING under root for details */ #include "lib/avl_tree.h" static inline int32_t KABI lbp_avl_tree_node_get_height(avl_tree_node_t *node) { return node == NULL ? -1 : node->height; } static inline int32_t KABI lbp_avl_tree_node_get_balance_factor(avl_tree_node_t *node) { if (node == NULL) return 0; return lbp_avl_tree_node_get_height(node->left) - lbp_avl_tree_node_get_height(node->right); } static avl_tree_node_t *KABI lbp_avl_tree_node_right_rotate(avl_tree_node_t *root) { avl_tree_node_t *left_children = root->left; //adjust parents first left_children->parent = root->parent; root->parent = left_children; if (left_children->right != NULL) left_children->right->parent = root; //perform rotation root->left = root->left->right; left_children->right = root; //adjust height root->height = lb_max_32(lbp_avl_tree_node_get_height(root->left), lbp_avl_tree_node_get_height(root->right)) + 1; left_children->height = lb_max_32(lbp_avl_tree_node_get_height(left_children->left), lbp_avl_tree_node_get_height(left_children->right)) + 1; return left_children; } static avl_tree_node_t *KABI lbp_avl_tree_node_left_rotate(avl_tree_node_t *root) { avl_tree_node_t *right_children = root->right; //adjust parents right_children->parent = root->parent; root->parent = right_children; if (right_children->left != NULL) right_children->left->parent = root; //perform rotation root->right = root->right->left; right_children->left = root; root->height = lb_max_32(lbp_avl_tree_node_get_height(root->left), lbp_avl_tree_node_get_height(root->right)) + 1; right_children->height = lb_max_32(lbp_avl_tree_node_get_height(right_children->left), lbp_avl_tree_node_get_height(right_children->right)) + 1; return right_children; } static avl_tree_node_t *KABI lbp_avl_tree_node_balance(avl_tree_node_t *node) { const int32_t bf = lbp_avl_tree_node_get_balance_factor(node); if (bf > 1) { const int32_t left_bf = lbp_avl_tree_node_get_balance_factor(node->left); if (left_bf >= 0) //left left return lbp_avl_tree_node_right_rotate(node); else { //left right node->left = lbp_avl_tree_node_left_rotate(node->left); return lbp_avl_tree_node_right_rotate(node); } } else if (bf < -1) { const int32_t right_bf = lbp_avl_tree_node_get_balance_factor(node->right); if (right_bf <= 0) { // right right return lbp_avl_tree_node_left_rotate(node); } else { // right left node->right = lbp_avl_tree_node_right_rotate(node->right); return lbp_avl_tree_node_left_rotate(node); } } else return node; } static avl_tree_node_t *KABI lbp_avl_tree_node_insert(avl_tree_node_t *root, avl_tree_node_t *node, callback_func_t compare, avl_tree_node_t *parent) { if (node == NULL || compare == NULL) return root; if (root == NULL) { node->parent = parent; return node; } const int32_t comp = compare(root, node); if (comp < 0) root->right = lbp_avl_tree_node_insert(root->right, node, compare, root); else if (comp == 0) return root; else root->left = lbp_avl_tree_node_insert(root->left, node, compare, root); root->height = lb_max_32(lbp_avl_tree_node_get_height(root->left), lbp_avl_tree_node_get_height(root->right)) + 1; return lbp_avl_tree_node_balance(root); } static void lbp_avl_tree_swap_nodes(avl_tree_node_t *node1, avl_tree_node_t *node2) { if (node1 == NULL || node2 == NULL) return; avl_tree_node_t *parent = NULL; avl_tree_node_t *child = NULL; avl_tree_node_t *temp = NULL; //swap node but does not change anything else other than node1,node2 if (node1->parent != NULL && node1->parent == node2) { parent = node2; child = node1; } else if (node2->parent != NULL && node2->parent == node1) { parent = node1; child = node2; } if (parent != NULL && child != NULL) { //connected case if (parent->parent != NULL) { if (parent->parent->left == parent) parent->parent->left = child; else parent->parent->right = child; } //update left/right for parent if (parent->left != NULL && child != parent->left) { parent->left->parent = child; } if (parent->right != NULL && child != parent->right) { parent->right->parent = child; } //update left/right for children if (child->left != NULL) child->left->parent = parent; if (child->right != NULL) child->right->parent = parent; child->parent = parent->parent; parent->parent = child; if (child == parent->left) { /* parent / \ children */ parent->left = child->left; child->left = parent; temp = parent->right; parent->right = child->right; child->right = temp; } else { /* parent / \ children */ parent->right = child->right; child->right = parent; temp = parent->left; parent->left = child->left; child->left = temp; } } else { //not connected case //adjust all the nodes other than node1,node2 if (node1->left != NULL) node1->left->parent = node2; if (node1->right != NULL) node1->right->parent = node2; if (node2->left != NULL) node2->left->parent = node1; if (node2->right != NULL) node2->right->parent = node1; if (node1->parent != NULL) { if (node1->parent->left == node1) node1->parent->left = node2; else node1->parent->right = node2; } if (node2->parent != NULL) { if (node2->parent->left == node2) node2->parent->left = node1; else node2->parent->right = node1; } //adjust node1,node2 temp = node1->parent; node1->parent = node2->parent; node2->parent = temp; temp = node1->left; node1->left = node2->left; node2->left = temp; temp = node1->right; node1->right = node2->right; node2->right = temp; } //swap height int32_t height = node1->height; node1->height = node2->height; node2->height = height; return; } static avl_tree_node_t *KABI lbp_avl_tree_node_delete(avl_tree_node_t *root, avl_tree_node_t *node, callback_func_t compare, avl_tree_node_t **deleted_node) { if (root == NULL || node == NULL || compare == NULL || deleted_node == NULL) return root; const int32_t comp = compare(root, node); if (comp < 0) root->right = lbp_avl_tree_node_delete(root->right, node, compare, deleted_node); else if (comp > 0) root->left = lbp_avl_tree_node_delete(root->left, node, compare, deleted_node); else { *deleted_node = root; // node with only one child or no child if ((root->left == NULL) || (root->right == NULL)) { avl_tree_node_t *child = root->left != NULL ? root->left : root->right; if (child == NULL) { // 0 child root = NULL; } else // 1 child { child->parent = root->parent; root = child; } } else { // node with two children: Get the inorder successor (smallest // in the right subtree) avl_tree_node_t *successor = lb_avl_tree_larger(root); //swap fields lbp_avl_tree_swap_nodes(successor, root); // Detach the inorder successor successor->right = lbp_avl_tree_node_delete(successor->right, root, compare, deleted_node); root = successor; } } if (root == NULL) return root; root->height = lb_max_32(lbp_avl_tree_node_get_height(root->left), lbp_avl_tree_node_get_height(root->right)) + 1; root = lbp_avl_tree_node_balance(root); return root; } static avl_tree_node_t *KABI lbp_avl_tree_node_search(avl_tree_node_t *root, avl_tree_node_t *node, callback_func_t compare) { if (root == NULL || compare == NULL) return NULL; const int32_t comp = compare(root, node); if (comp < 0) return lbp_avl_tree_node_search(root->right, node, compare); else if (comp == 0) return root; else return lbp_avl_tree_node_search(root->left, node, compare); } static void KABI lbp_avl_tree_node_init(avl_tree_node_t *it) { if (it != NULL) { it->height = 0; it->left = NULL; it->right = NULL; it->parent = NULL; } return; } avl_tree_node_t *KABI lb_avl_tree_smallest(avl_tree_t *tree) { if (tree == NULL) return NULL; avl_tree_node_t *entry = tree->root; if (entry == NULL) return NULL; while (entry->left != NULL) entry = entry->left; return entry; } avl_tree_node_t *KABI lb_avl_tree_largest(avl_tree_t *tree) { if (tree == NULL) return NULL; avl_tree_node_t *entry = tree->root; if (entry == NULL) return NULL; while (entry->right != NULL) entry = entry->right; return entry; } avl_tree_node_t *KABI lb_avl_tree_larger(avl_tree_node_t *it) { if (it == NULL) return NULL; avl_tree_node_t *root = it; if (root->right != NULL) { root = root->right; while (root->left != NULL) root = root->left; return root; } else { while (root->parent != NULL) { if (root->parent->left == root) return root->parent; root = root->parent; } return NULL; } } avl_tree_node_t *KABI lb_avl_tree_smaller(avl_tree_node_t *it) { if (it == NULL) return NULL; avl_tree_node_t *root = it; if (root->left != NULL) { root = root->left; while (root->right != NULL) root = root->right; return root; } else { while (root->parent != NULL) { if (root->parent->right == root) return root->parent; root = root->parent; } return NULL; } } avl_tree_node_t *KABI lb_avl_tree_search(avl_tree_t *tree, avl_tree_node_t *node) { return lbp_avl_tree_node_search(tree->root, node, tree->compare); } void KABI lb_avl_tree_insert(avl_tree_t *tree, avl_tree_node_t *data) { if (tree != NULL && data != NULL) { lbp_avl_tree_node_init(data); tree->root = lbp_avl_tree_node_insert(tree->root, data, tree->compare, NULL); } return; } avl_tree_node_t *KABI lb_avl_tree_delete(avl_tree_t *tree, avl_tree_node_t *data) { avl_tree_node_t *node = NULL; if (tree != NULL && data != NULL) { tree->root = lbp_avl_tree_node_delete(tree->root, data, tree->compare, &node); } return node; } int32_t KABI lb_avl_tree_size(avl_tree_t *tree) { if (tree == NULL) return -1; if (tree->root == NULL) return 0; int32_t size = 0; avl_tree_node_t *entry = lb_avl_tree_smallest(tree); while (entry != NULL) { size++; entry = lb_avl_tree_larger(entry); } return size; } void KABI lb_avl_tree_init(avl_tree_t *tree, callback_func_t compare) { if (tree != NULL) { tree->compare = compare; tree->root = NULL; } return; } // TESTING STUFF static int32_t KABI lbp_avl_tree_node_calculate_height(avl_tree_node_t *tree) { if (tree == NULL) return -1; return lb_max_32(lbp_avl_tree_node_calculate_height(tree->left), lbp_avl_tree_node_calculate_height(tree->right)) + 1; } static bool KABI lbp_avl_tree_node_test(avl_tree_node_t *tree, callback_func_t compare) { if (tree == NULL) return true; if (lbp_avl_tree_node_get_balance_factor(tree) < -1 || lbp_avl_tree_node_get_balance_factor(tree) > 1 || lbp_avl_tree_node_calculate_height(tree) != tree->height) return false; if (tree->left != NULL) { if (tree->left->parent != tree) return false; } if (tree->right != NULL) { if (tree->right->parent != tree) return false; } if (compare != NULL) { if ((tree->right != NULL && compare(tree, tree->right) > 0) || (tree->left != NULL && compare(tree, tree->left) < 0)) return false; } return lbp_avl_tree_node_test(tree->left, compare) && lbp_avl_tree_node_test(tree->right, compare); } bool KABI lb_avl_tree_validate(avl_tree_t *tree) { if (tree == NULL) return true; return lbp_avl_tree_node_test(tree->root, tree->compare); }