243 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			243 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * Copyright (c) 2006-2022, RT-Thread Development Team | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  * | ||
|  |  * Change Logs: | ||
|  |  * Date           Author       Notes | ||
|  |  * 2019-10-12     Jesven       first version | ||
|  |  * 2022-11-14     WangXiaoyao  Optimize footprint and performance | ||
|  |  *                             Export as ADT for generic use case | ||
|  |  */ | ||
|  | #include <stddef.h>
 | ||
|  | #include <stdint.h>
 | ||
|  | 
 | ||
|  | #include "avl.h"
 | ||
|  | 
 | ||
|  | #define HEIGHT_OF(node) ((node) ? (node)->height : 0)
 | ||
|  | #define IS_RCHILD(node) (!((node) - ((node)->parent->avl_right)))
 | ||
|  | #define IS_LCHILD(node) (!((node) - ((node)->parent->avl_left)))
 | ||
|  | #define NODE_PLACE(node)                                                       \
 | ||
|  |     IS_LCHILD(node) ? &(node)->parent->avl_left : &(node)->parent->avl_right | ||
|  | 
 | ||
|  | static inline void rotate_right(struct util_avl_struct *axis, | ||
|  |                                 struct util_avl_struct *lchild, | ||
|  |                                 struct util_avl_struct *lrchild, | ||
|  |                                 struct util_avl_struct **nodeplace, | ||
|  |                                 size_t lrheight) | ||
|  | { | ||
|  |     axis->avl_left = lrchild; | ||
|  |     lchild->avl_right = axis; | ||
|  | 
 | ||
|  |     axis->height = lrheight + 1; | ||
|  |     lchild->height = axis->height + 1; | ||
|  | 
 | ||
|  |     lchild->parent = axis->parent; | ||
|  |     axis->parent = lchild; | ||
|  | 
 | ||
|  |     *nodeplace = lchild; | ||
|  |     if (lrchild != NULL) | ||
|  |         lrchild->parent = axis; | ||
|  | } | ||
|  | 
 | ||
|  | static inline void midmount_right(struct util_avl_struct *axis, | ||
|  |                                   struct util_avl_struct *lchild, | ||
|  |                                   struct util_avl_struct *lrchild, | ||
|  |                                   struct util_avl_struct **nodeplace, | ||
|  |                                   size_t lrheight) | ||
|  | { | ||
|  |     lchild->avl_right = lrchild->avl_left; | ||
|  |     axis->avl_left = lrchild->avl_right; | ||
|  |     lrchild->avl_left = lchild; | ||
|  |     lrchild->avl_right = axis; | ||
|  | 
 | ||
|  |     lrchild->height = lchild->height; | ||
|  |     lchild->height = lrheight; | ||
|  |     axis->height = lrheight; | ||
|  | 
 | ||
|  |     lrchild->parent = axis->parent; | ||
|  |     lchild->parent = lrchild; | ||
|  |     axis->parent = lrchild; | ||
|  |     if (lchild->avl_right != NULL) | ||
|  |         lchild->avl_right->parent = lchild; | ||
|  |     if (axis->avl_left != NULL) | ||
|  |         axis->avl_left->parent = axis; | ||
|  |     *nodeplace = lrchild; | ||
|  | } | ||
|  | 
 | ||
|  | static inline void rotate_left(struct util_avl_struct *axis, | ||
|  |                                struct util_avl_struct *rchild, | ||
|  |                                struct util_avl_struct *rlchild, | ||
|  |                                struct util_avl_struct **nodeplace, | ||
|  |                                size_t rlheight) | ||
|  | { | ||
|  |     axis->avl_right = rlchild; | ||
|  |     rchild->avl_left = axis; | ||
|  | 
 | ||
|  |     axis->height = rlheight + 1; | ||
|  |     rchild->height = axis->height + 1; | ||
|  | 
 | ||
|  |     rchild->parent = axis->parent; | ||
|  |     axis->parent = rchild; | ||
|  | 
 | ||
|  |     *nodeplace = rchild; | ||
|  |     if (rlchild != NULL) | ||
|  |         rlchild->parent = axis; | ||
|  | } | ||
|  | 
 | ||
|  | static inline void midmount_left(struct util_avl_struct *axis, | ||
|  |                                  struct util_avl_struct *rchild, | ||
|  |                                  struct util_avl_struct *rlchild, | ||
|  |                                  struct util_avl_struct **nodeplace, | ||
|  |                                  size_t rlheight) | ||
|  | { | ||
|  |     rchild->avl_left = rlchild->avl_right; | ||
|  |     axis->avl_right = rlchild->avl_left; | ||
|  |     rlchild->avl_right = rchild; | ||
|  |     rlchild->avl_left = axis; | ||
|  | 
 | ||
|  |     rlchild->height = rchild->height; | ||
|  |     rchild->height = rlheight; | ||
|  |     axis->height = rlheight; | ||
|  | 
 | ||
|  |     rlchild->parent = axis->parent; | ||
|  |     rchild->parent = rlchild; | ||
|  |     axis->parent = rlchild; | ||
|  |     if (rchild->avl_left != NULL) | ||
|  |         rchild->avl_left->parent = rchild; | ||
|  |     if (axis->avl_right != NULL) | ||
|  |         axis->avl_right->parent = axis; | ||
|  | 
 | ||
|  |     *nodeplace = rlchild; | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * @brief avl insertion & delete conceptually contain 2 stage | ||
|  |  * 1. insertion/delete of reference | ||
|  |  * 2. rebalance | ||
|  |  */ | ||
|  | 
 | ||
|  | void util_avl_rebalance(struct util_avl_struct *node, | ||
|  |                         struct util_avl_root *root) | ||
|  | { | ||
|  |     if (!node) | ||
|  |         return; | ||
|  | 
 | ||
|  |     struct util_avl_struct *axis = node; | ||
|  |     struct util_avl_struct **nodeplace; | ||
|  |     do | ||
|  |     { | ||
|  |         struct util_avl_struct *lchild = axis->avl_left; | ||
|  |         struct util_avl_struct *rchild = axis->avl_right; | ||
|  |         nodeplace = axis->parent ? NODE_PLACE(axis) : &root->root_node; | ||
|  |         int lheight = HEIGHT_OF(lchild); | ||
|  |         int rheight = HEIGHT_OF(rchild); | ||
|  |         if (rheight + 1 < lheight) | ||
|  |         { | ||
|  |             struct util_avl_struct *lrchild = lchild->avl_right; | ||
|  |             size_t lrheight = HEIGHT_OF(lrchild); | ||
|  |             if (HEIGHT_OF(lchild->avl_left) >= lrheight) | ||
|  |             { | ||
|  |                 rotate_right(axis, lchild, lrchild, nodeplace, lrheight); | ||
|  |                 axis = lchild->parent; | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 midmount_right(axis, lchild, lrchild, nodeplace, lrheight); | ||
|  |                 axis = lrchild->parent; | ||
|  |             } | ||
|  |         } | ||
|  |         else if (lheight + 1 < rheight) | ||
|  |         { | ||
|  |             struct util_avl_struct *rlchild = rchild->avl_left; | ||
|  |             size_t rlheight = HEIGHT_OF(rlchild); | ||
|  |             if (HEIGHT_OF(rchild->avl_right) >= rlheight) | ||
|  |             { | ||
|  |                 rotate_left(axis, rchild, rlchild, nodeplace, rlheight); | ||
|  |                 axis = rchild->parent; | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 midmount_left(axis, rchild, rlchild, nodeplace, rlheight); | ||
|  |                 axis = rlchild->parent; | ||
|  |             } | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             int height = (lheight < rheight ? rheight : lheight) + 1; | ||
|  |             if (height == axis->height) | ||
|  |                 break; | ||
|  |             axis->height = height; | ||
|  |             axis = axis->parent; | ||
|  |         } | ||
|  |     } while (axis); | ||
|  | } | ||
|  | 
 | ||
|  | void util_avl_remove(struct util_avl_struct *node, struct util_avl_root *root) | ||
|  | { | ||
|  |     struct util_avl_struct **nodeplace; | ||
|  | 
 | ||
|  |     if (root->root_node == NULL) | ||
|  |         return; | ||
|  | 
 | ||
|  |     if (node->parent != NULL) | ||
|  |     { | ||
|  |         nodeplace = NODE_PLACE(node); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         nodeplace = &root->root_node; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* deletion */ | ||
|  |     if (node->avl_right == NULL) | ||
|  |     { | ||
|  |         *nodeplace = node->avl_left; | ||
|  |         if (node->avl_left != NULL) | ||
|  |             node->avl_left->parent = node->parent; | ||
|  |         node = node->parent; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         struct util_avl_struct *rchild = node->avl_right; | ||
|  |         if (rchild->avl_left == NULL) | ||
|  |         { | ||
|  |             *nodeplace = rchild; | ||
|  |             rchild->avl_left = node->avl_left; | ||
|  |             if (rchild->avl_left != NULL) | ||
|  |                 rchild->avl_left->parent = rchild; | ||
|  |             rchild->parent = node->parent; | ||
|  |             util_avl_rebalance(rchild, root); | ||
|  |             node = rchild->parent; | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             struct util_avl_struct *successor = rchild->avl_left; | ||
|  |             struct util_avl_struct *sparent = rchild; | ||
|  |             while (successor->avl_left != NULL) | ||
|  |             { | ||
|  |                 sparent = successor; | ||
|  |                 successor = successor->avl_left; | ||
|  |             } | ||
|  |             *nodeplace = successor; | ||
|  |             sparent->avl_left = successor->avl_right; | ||
|  |             successor->avl_left = node->avl_left; | ||
|  |             successor->avl_right = node->avl_right; | ||
|  | 
 | ||
|  |             if (successor->avl_left != NULL) | ||
|  |                 successor->avl_left->parent = successor; | ||
|  |             successor->avl_right->parent = successor; | ||
|  | 
 | ||
|  |             if (sparent->avl_left != NULL) | ||
|  |                 sparent->avl_left->parent = sparent; | ||
|  |             successor->parent = node->parent; | ||
|  |             util_avl_rebalance(sparent, root); | ||
|  |             node = successor; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /* rebalance */ | ||
|  |     util_avl_rebalance(node, root); | ||
|  |     return; | ||
|  | } |