370 lines
10 KiB
C
370 lines
10 KiB
C
/*
|
|
* Copyright (c) 2020 AIIT XUOS Lab
|
|
* XiUOS is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
*/
|
|
|
|
/**
|
|
* @file: avl_tree.c
|
|
* @brief: avl_tree file
|
|
* @version: 1.0
|
|
* @author: AIIT XUOS Lab
|
|
* @date: 2020/3/15
|
|
*
|
|
*/
|
|
|
|
#include "xs_avltree.h"
|
|
#include <string.h>
|
|
#include <xs_kdbg.h>
|
|
#include <xs_klist.h>
|
|
#include <xs_memory.h>
|
|
|
|
/**
|
|
* This function will return the node height of the avl tree
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @return 0
|
|
*/
|
|
static uint32 AvlTreeGetNodeHeight(AvlNodeType avl_node)
|
|
{
|
|
if(avl_node) {
|
|
return AVL_MAX(AvlTreeGetNodeHeight(avl_node->left), AvlTreeGetNodeHeight(avl_node->right)) + 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will return the node balance factor of the avl tree
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
*/
|
|
static int32 AvlTreeGetNodeBalanceFactor(AvlNodeType avl_node)
|
|
{
|
|
if(avl_node) {
|
|
return AvlTreeGetNodeHeight(avl_node->left) - AvlTreeGetNodeHeight(avl_node->right);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will support right rotate to balance the avl tree(eg. LL case)
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @return avl tree node
|
|
*/
|
|
static AvlNodeType AvlTreeSetRightRotate(AvlNodeType avl_node)
|
|
{
|
|
NULL_PARAM_CHECK(avl_node);
|
|
|
|
AvlNodeType new_node = avl_node->left;
|
|
|
|
avl_node->left = new_node->right;
|
|
new_node->right = avl_node;
|
|
|
|
new_node->height = AVL_MAX(AvlTreeGetNodeHeight(new_node->left), AvlTreeGetNodeHeight(new_node->right)) + 1;
|
|
avl_node->height = AVL_MAX(AvlTreeGetNodeHeight(avl_node->left), AvlTreeGetNodeHeight(avl_node->right)) + 1;
|
|
|
|
return new_node;
|
|
}
|
|
|
|
/**
|
|
* This function will support left rotate to balance the avl tree(eg. RR case)
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @return avl tree node
|
|
*/
|
|
static AvlNodeType AvlTreeSetLeftRotate(AvlNodeType avl_node)
|
|
{
|
|
NULL_PARAM_CHECK(avl_node);
|
|
|
|
AvlNodeType new_node = avl_node->right;
|
|
|
|
avl_node->right = new_node->left;
|
|
new_node->left = avl_node;
|
|
|
|
new_node->height = AVL_MAX(AvlTreeGetNodeHeight(new_node->left), AvlTreeGetNodeHeight(new_node->right)) + 1;
|
|
avl_node->height = AVL_MAX(AvlTreeGetNodeHeight(avl_node->left), AvlTreeGetNodeHeight(avl_node->right)) + 1;
|
|
|
|
return new_node;
|
|
}
|
|
|
|
/**
|
|
* This function will support left and right rotate to balance the avl tree(eg. LR case)
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @return avl tree node
|
|
*/
|
|
static AvlNodeType AvlTreeSetLRRotate(AvlNodeType avl_node)
|
|
{
|
|
NULL_PARAM_CHECK(avl_node);
|
|
|
|
AvlNodeType new_node = NONE;
|
|
AvlNodeType left_node = avl_node->left;
|
|
|
|
/*step1 : Left rotate*/
|
|
avl_node->left = AvlTreeSetLeftRotate(left_node);
|
|
|
|
/*step2 : Right rotate*/
|
|
new_node = AvlTreeSetRightRotate(avl_node);
|
|
|
|
return new_node;
|
|
}
|
|
|
|
/**
|
|
* This function will support right and left rotate to balance the avl tree(eg. RL case)
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @return avl tree node
|
|
*/
|
|
static AvlNodeType AvlTreeSetRLRotate(AvlNodeType avl_node)
|
|
{
|
|
NULL_PARAM_CHECK(avl_node);
|
|
|
|
AvlNodeType new_node = NONE;
|
|
AvlNodeType right_node = avl_node->right;
|
|
|
|
/*step1 : Right rotate*/
|
|
avl_node->right = AvlTreeSetRightRotate(right_node);
|
|
|
|
/*step2 : Left rotate*/
|
|
new_node = AvlTreeSetLeftRotate(avl_node);
|
|
|
|
return new_node;
|
|
}
|
|
|
|
/**
|
|
* This function will balance the avl tree when inserting or deleting node
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @return avl tree node
|
|
*/
|
|
static AvlNodeType AvlTreeBalance(AvlNodeType avl_node)
|
|
{
|
|
if(avl_node)
|
|
{
|
|
AvlNodeType new_node = NONE;
|
|
uint32 avlnode_BF = AVL_ABS(AvlTreeGetNodeBalanceFactor(avl_node));
|
|
|
|
if(avlnode_BF > 1) {
|
|
if(AvlTreeGetNodeBalanceFactor(avl_node->left) > 0) {
|
|
/*LL case*/
|
|
new_node = AvlTreeSetRightRotate(avl_node);
|
|
} else if(AvlTreeGetNodeBalanceFactor(avl_node->left) < 0) {
|
|
/*LR case*/
|
|
new_node = AvlTreeSetLRRotate(avl_node);
|
|
} else if(AvlTreeGetNodeBalanceFactor(avl_node->right) < 0) {
|
|
/*RR case*/
|
|
new_node = AvlTreeSetLeftRotate(avl_node);
|
|
} else if(AvlTreeGetNodeBalanceFactor(avl_node->right) > 0) {
|
|
/*RL case*/
|
|
new_node = AvlTreeSetRLRotate(avl_node);
|
|
}
|
|
} else {
|
|
/*the avl tree is balanced, no need to rebalance*/
|
|
new_node = avl_node;
|
|
}
|
|
|
|
return new_node;
|
|
|
|
} else {
|
|
return NONE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will insert data to the avl tree
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @param data input data
|
|
*/
|
|
AvlNodeType AvlTreeInsertNode(AvlNodeType avl_node, int32 data)
|
|
{
|
|
AvlNodeType new_node = NONE;
|
|
|
|
if(NONE == avl_node) {
|
|
new_node = x_malloc(sizeof(struct AvlNode));
|
|
if(NONE == new_node) {
|
|
KPrintf("AvlTreeInsertNode malloc AvlNode failed\n");
|
|
x_free(new_node);
|
|
return NONE;
|
|
}
|
|
new_node->data = data;
|
|
new_node->left = NONE;
|
|
new_node->right = NONE;
|
|
new_node->height = 1;
|
|
avl_node = new_node;
|
|
} else if(data == avl_node->data) {
|
|
/*input data is already existed*/
|
|
KPrintf("the input data is already existed. just return\n");
|
|
return avl_node;
|
|
} else {
|
|
if(avl_node->data < data) {
|
|
avl_node->right = AvlTreeInsertNode(avl_node->right, data);
|
|
if(NONE == avl_node->right) {
|
|
KPrintf("AvlTreeInsertNode find right avl_node data failed\n");
|
|
return NONE;
|
|
}
|
|
} else {
|
|
avl_node->left = AvlTreeInsertNode(avl_node->left, data);
|
|
if(NONE == avl_node->left) {
|
|
KPrintf("AvlTreeInsertNode find left avl_node data failed\n");
|
|
return NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return AvlTreeBalance(avl_node);
|
|
}
|
|
|
|
/**
|
|
* This function will find the pre node of the avl_node
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @return avl tree node
|
|
*/
|
|
static AvlNodeType AvlTreeFindPreNode(AvlNodeType avl_node)
|
|
{
|
|
NULL_PARAM_CHECK(avl_node);
|
|
|
|
AvlNodeType pre_node = NONE;
|
|
|
|
if(avl_node->left) {
|
|
if(avl_node->left->right) {
|
|
pre_node = avl_node->left->right;
|
|
while(pre_node->right) {
|
|
pre_node = pre_node->right;
|
|
}
|
|
} else {
|
|
pre_node = avl_node->left;
|
|
}
|
|
} else {
|
|
pre_node = avl_node;
|
|
}
|
|
|
|
return pre_node;
|
|
}
|
|
|
|
/**
|
|
* This function will delete a certain node, ultimate target is to find the leaf node
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @param data delete data
|
|
* @return avl tree node
|
|
*/
|
|
static AvlNodeType AvlTreeDeleteLeafNode(AvlNodeType avl_node)
|
|
{
|
|
AvlNodeType pre_node = NONE;
|
|
|
|
if((NONE == avl_node->left) && (NONE == avl_node->right)) {
|
|
/*Leaf Node*/
|
|
avl_node = NONE;
|
|
x_free(avl_node);
|
|
} else if(NONE == avl_node->left) {
|
|
/*Right child is Leaf Node*/
|
|
avl_node->data = avl_node->right->data;
|
|
avl_node->right = NONE;
|
|
x_free(avl_node->right);
|
|
} else if(NONE == avl_node->right) {
|
|
/*Left child is Leaf Node*/
|
|
avl_node->data = avl_node->left->data;
|
|
avl_node->left = NONE;
|
|
x_free(avl_node->left);
|
|
} else {
|
|
/*Find the pre node to replace the avl node, then delete the pre node*/
|
|
pre_node = AvlTreeFindPreNode(avl_node);
|
|
if(pre_node) {
|
|
avl_node->data = pre_node->data;
|
|
avl_node->left = AvlTreeDeleteNode(avl_node->left, pre_node->data);
|
|
}
|
|
}
|
|
|
|
return avl_node;
|
|
}
|
|
|
|
/**
|
|
* This function will delete data from the avl tree
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @param data delete data
|
|
*/
|
|
AvlNodeType AvlTreeDeleteNode(AvlNodeType avl_node, int32 data)
|
|
{
|
|
if(avl_node) {
|
|
if(data == avl_node->data) {
|
|
avl_node = AvlTreeDeleteLeafNode(avl_node);
|
|
} else {
|
|
if(avl_node->data < data) {
|
|
avl_node->right = AvlTreeDeleteNode(avl_node->right, data);
|
|
} else {
|
|
avl_node->left = AvlTreeDeleteNode(avl_node->left, data);
|
|
}
|
|
}
|
|
|
|
return AvlTreeBalance(avl_node);
|
|
} else {
|
|
KPrintf("AvlTreeDeleteNode cannot find the delete data\n");
|
|
return NONE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will modify certain data of the avl tree
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @param src_data src data
|
|
* @param dst_data dst data
|
|
*/
|
|
AvlNodeType AvlNodeModifyNode(AvlNodeType avl_node, int32 src_data, int32 dst_data)
|
|
{
|
|
AvlNodeType dst_node = NONE;
|
|
|
|
if(avl_node) {
|
|
/*Step1 : delete the src data node*/
|
|
avl_node = AvlTreeDeleteNode(avl_node, src_data);
|
|
|
|
/*Step2 : insert the dst data node*/
|
|
dst_node = AvlTreeInsertNode(avl_node, dst_data);
|
|
|
|
} else {
|
|
KPrintf("AvlNodeModifyNode cannot find the src data node\n");
|
|
return NONE;
|
|
}
|
|
|
|
return dst_node;
|
|
}
|
|
|
|
/**
|
|
* This function will return the avl node which has the data
|
|
*
|
|
* @param avl_node avl tree node descriptor
|
|
* @param data data
|
|
*/
|
|
AvlNodeType AvlNodeSearchNode(AvlNodeType avl_node, int32 data)
|
|
{
|
|
AvlNodeType dst_node = NONE;
|
|
|
|
if(avl_node) {
|
|
if(data == avl_node->data) {
|
|
dst_node = avl_node;
|
|
KPrintf("AvlNodeSearchNode %d is existed return the node\n", avl_node->data);
|
|
} else if(avl_node->data < data) {
|
|
dst_node = AvlNodeSearchNode(avl_node->right, data);
|
|
} else {
|
|
dst_node = AvlNodeSearchNode(avl_node->left, data);
|
|
}
|
|
} else {
|
|
KPrintf("AvlNodeSearchNode avl_node is NONE.\n");
|
|
return NONE;
|
|
}
|
|
|
|
return dst_node;
|
|
}
|