| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- /*
- * Copyright (c) 2006-2025 RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2019-10-12 Jesven first version
- */
- #include <rtthread.h>
- #include <lwp_avl.h>
- /**
- * @brief Rebalances an AVL tree after insertion or deletion
- *
- * @param[in,out] nodeplaces_ptr Pointer to stack of node pointers that need rebalancing
- * @param[in] count Number of nodes in the stack that need rebalancing
- *
- * @note This function performs AVL tree rebalancing by checking and correcting height imbalances
- * between left and right subtrees. It handles:
- * - Left-left case (single right rotation)
- * - Left-right case (double rotation: left then right)
- * - Right-right case (single left rotation)
- * - Right-left case (double rotation: right then left)
- */
- static void lwp_avl_rebalance(struct lwp_avl_struct ***nodeplaces_ptr, int count)
- {
- for (; count > 0; count--)
- {
- struct lwp_avl_struct **nodeplace = *--nodeplaces_ptr;
- struct lwp_avl_struct *node = *nodeplace;
- struct lwp_avl_struct *nodeleft = node->avl_left;
- struct lwp_avl_struct *noderight = node->avl_right;
- int heightleft = heightof(nodeleft);
- int heightright = heightof(noderight);
- if (heightright + 1 < heightleft)
- {
- struct lwp_avl_struct *nodeleftleft = nodeleft->avl_left;
- struct lwp_avl_struct *nodeleftright = nodeleft->avl_right;
- int heightleftright = heightof(nodeleftright);
- if (heightof(nodeleftleft) >= heightleftright)
- {
- node->avl_left = nodeleftright;
- nodeleft->avl_right = node;
- nodeleft->avl_height = 1 + (node->avl_height = 1 + heightleftright);
- *nodeplace = nodeleft;
- }
- else
- {
- nodeleft->avl_right = nodeleftright->avl_left;
- node->avl_left = nodeleftright->avl_right;
- nodeleftright->avl_left = nodeleft;
- nodeleftright->avl_right = node;
- nodeleft->avl_height = node->avl_height = heightleftright;
- nodeleftright->avl_height = heightleft;
- *nodeplace = nodeleftright;
- }
- }
- else if (heightleft + 1 < heightright)
- {
- struct lwp_avl_struct *noderightright = noderight->avl_right;
- struct lwp_avl_struct *noderightleft = noderight->avl_left;
- int heightrightleft = heightof(noderightleft);
- if (heightof(noderightright) >= heightrightleft)
- {
- node->avl_right = noderightleft;
- noderight->avl_left = node;
- noderight->avl_height = 1 + (node->avl_height = 1 + heightrightleft);
- *nodeplace = noderight;
- }
- else
- {
- noderight->avl_left = noderightleft->avl_right;
- node->avl_right = noderightleft->avl_left;
- noderightleft->avl_right = noderight;
- noderightleft->avl_left = node;
- noderight->avl_height = node->avl_height = heightrightleft;
- noderightleft->avl_height = heightright;
- *nodeplace = noderightleft;
- }
- }
- else
- {
- int height = (heightleft < heightright ? heightright : heightleft) + 1;
- if (height == node->avl_height)
- break;
- node->avl_height = height;
- }
- }
- }
- /**
- * @brief Removes a node from an AVL tree while maintaining balance
- *
- * @param[in] node_to_delete The node to be removed from the AVL tree
- * @param[in,out] ptree Pointer to the root node pointer of the AVL tree
- *
- * @note This function removes the specified node from the AVL tree and performs
- * necessary rebalancing operations. It handles both cases where the node
- * has no left child (simple removal) and where it has a left child (finding
- * the rightmost node in the left subtree as replacement).
- * It uses a stack to track the removal path for rebalancing.
- */
- void lwp_avl_remove(struct lwp_avl_struct *node_to_delete, struct lwp_avl_struct **ptree)
- {
- avl_key_t key = node_to_delete->avl_key;
- struct lwp_avl_struct **nodeplace = ptree;
- struct lwp_avl_struct **stack[avl_maxheight];
- uint32_t stack_count = 0;
- struct lwp_avl_struct ***stack_ptr = &stack[0]; /* = &stack[stackcount] */
- struct lwp_avl_struct **nodeplace_to_delete;
- for (;;)
- {
- struct lwp_avl_struct *node = *nodeplace;
- if (node == AVL_EMPTY)
- {
- return;
- }
- *stack_ptr++ = nodeplace;
- stack_count++;
- if (key == node->avl_key)
- break;
- if (key < node->avl_key)
- nodeplace = &node->avl_left;
- else
- nodeplace = &node->avl_right;
- }
- nodeplace_to_delete = nodeplace;
- if (node_to_delete->avl_left == AVL_EMPTY)
- {
- *nodeplace_to_delete = node_to_delete->avl_right;
- stack_ptr--;
- stack_count--;
- }
- else
- {
- struct lwp_avl_struct ***stack_ptr_to_delete = stack_ptr;
- struct lwp_avl_struct **nodeplace = &node_to_delete->avl_left;
- struct lwp_avl_struct *node;
- for (;;)
- {
- node = *nodeplace;
- if (node->avl_right == AVL_EMPTY)
- break;
- *stack_ptr++ = nodeplace;
- stack_count++;
- nodeplace = &node->avl_right;
- }
- *nodeplace = node->avl_left;
- node->avl_left = node_to_delete->avl_left;
- node->avl_right = node_to_delete->avl_right;
- node->avl_height = node_to_delete->avl_height;
- *nodeplace_to_delete = node;
- *stack_ptr_to_delete = &node->avl_left;
- }
- lwp_avl_rebalance(stack_ptr, stack_count);
- }
- /**
- * @brief Inserts a new node into an AVL tree while maintaining balance
- *
- * @param[in] new_node The new node to be inserted into the AVL tree
- * @param[in,out] ptree Pointer to the root node pointer of the AVL tree
- *
- * @note Uses a stack to track the insertion path for rebalancing
- */
- void lwp_avl_insert(struct lwp_avl_struct *new_node, struct lwp_avl_struct **ptree)
- {
- avl_key_t key = new_node->avl_key;
- struct lwp_avl_struct **nodeplace = ptree;
- struct lwp_avl_struct **stack[avl_maxheight];
- int stack_count = 0;
- struct lwp_avl_struct ***stack_ptr = &stack[0]; /* = &stack[stackcount] */
- for (;;)
- {
- struct lwp_avl_struct *node = *nodeplace;
- if (node == AVL_EMPTY)
- break;
- *stack_ptr++ = nodeplace;
- stack_count++;
- if (key < node->avl_key)
- nodeplace = &node->avl_left;
- else
- nodeplace = &node->avl_right;
- }
- new_node->avl_left = AVL_EMPTY;
- new_node->avl_right = AVL_EMPTY;
- new_node->avl_height = 1;
- *nodeplace = new_node;
- lwp_avl_rebalance(stack_ptr, stack_count);
- }
- /**
- * @brief Finds a node in an AVL tree by key
- *
- * @param[in] key The key to search for in the AVL tree
- * @param[in] ptree Pointer to the root node of the AVL tree
- *
- * @return struct lwp_avl_struct* Pointer to the found node, or NULL if not found
- *
- * @note This function searches the AVL tree for a node with the specified key.
- * It performs a standard binary search by comparing keys and traversing
- * left or right subtrees accordingly.
- */
- struct lwp_avl_struct *lwp_avl_find(avl_key_t key, struct lwp_avl_struct *ptree)
- {
- for (;;)
- {
- if (ptree == AVL_EMPTY)
- {
- return (struct lwp_avl_struct *)0;
- }
- if (key == ptree->avl_key)
- break;
- if (key < ptree->avl_key)
- ptree = ptree->avl_left;
- else
- ptree = ptree->avl_right;
- }
- return ptree;
- }
- /**
- * @brief Recursively traverses an AVL tree and applies a function to each node
- *
- * @param[in] ptree Pointer to the root node of the AVL tree
- * @param[in] fun Callback function to apply to each node
- * @param[in,out] arg Additional argument passed to the callback function
- *
- * @return int Returns the last result from the callback function (0 if all nodes processed)
- *
- * @note This function performs an in-order traversal of the AVL tree, applying the
- * provided callback function to each node. The traversal can be stopped early
- * if the callback returns a non-zero value.
- */
- int lwp_avl_traversal(struct lwp_avl_struct *ptree, int (*fun)(struct lwp_avl_struct *, void *), void *arg)
- {
- int ret;
- if (!ptree)
- {
- return 0;
- }
- if (ptree->avl_left)
- {
- ret = lwp_avl_traversal(ptree->avl_left, fun, arg);
- if (ret != 0)
- {
- return ret;
- }
- }
- ret = (*fun)(ptree, arg);
- if (ret != 0)
- {
- return ret;
- }
- if (ptree->avl_right)
- {
- ret = lwp_avl_traversal(ptree->avl_right, fun, arg);
- if (ret != 0)
- {
- return ret;
- }
- }
- return ret;
- }
- /**
- * @brief Finds the first (leftmost) node in an AVL tree
- *
- * @param[in] ptree Pointer to the root node of the AVL tree
- *
- * @return struct lwp_avl_struct* Pointer to the leftmost node, or NULL if tree is empty
- *
- * @note This function traverses the AVL tree to find the leftmost node, which represents
- * the minimum element in the tree. It's commonly used for ordered traversal starting point.
- */
- rt_weak struct lwp_avl_struct* lwp_map_find_first(struct lwp_avl_struct* ptree)
- {
- if (ptree == AVL_EMPTY)
- {
- return (struct lwp_avl_struct *)0;
- }
- while (1)
- {
- if (!ptree->avl_left)
- {
- break;
- }
- ptree = ptree->avl_left;
- }
- return ptree;
- }
|