228 lines
6.7 KiB
C
228 lines
6.7 KiB
C
|
/*
|
||
|
* Copyright (c) 2006-2020, 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>
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|