rt-thread/components/lwp/lwp_avl.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;
}