目录
一、AVL 树简介
AVL树 是平衡二叉树,其具有如下几个性质:
- 必须是二叉树;
- 必须是一颗空树或者其左右子树的高度之差的绝对值不超过 1。
- 对于每个节点,其左孩子比这个节点小,右孩子比这个节点大。
平衡二叉树的作用主要是为了避免普通二叉查找树在极端情况下(全部节点只有左孩子或者全部节点只有右孩子)会变成链表那样,在操作的时候影响性能。
二、AVL树自平衡
判断 AVL树 失衡形状时,先找出失衡节点,当失衡节点的左子树高度大于右子树的时候,记为
L
,否则记为R
,若左子树的高度大于右子树,再判断失衡节点的左孩子的左子树与右子树的关系,若失衡节点的左孩子的左子树高度大于失衡节点的左子树的右子树,则记为LL
型,否则记为LR
型;同理,若失衡节点的右孩子高度大于左子树的高度时,可根据失衡节点右孩子的左右子树高度分别判断为RR
型 和RL
型。
2.1. LL 型
- 简单的
LL
型旋转
依次插入 5、3、2 时如下图所示:
如上图所示,当插入节点 2 时,导致节点 5 失衡,此时节点 5 左子树的不小于其右子树的高度,且节点 5 的左孩子(节点 3)的左子树高度不小于右子树高度,所以进行LL
型旋转。
- 复杂的
LL
型旋转
依次插入 5、6、3、4、2、1 时如下图所示:
如上图所示,当插入节点 1 时,导致节点 5 失衡,此时节点 5 左子树的高度不小于其右子树的高度,且节点 5 的左孩子(节点 3)的左子树高度不小于右子树高度,所以进行LL
型旋转。
LL
型旋转步骤
- 假设失衡节点为节点 N,先暂存节点 N 的左孩子为节点 tmp;
- 令节点 N 的左孩子为节点 tmp 的右孩子;
- 令节点 tmp 的右孩子为节点 N;
- 更新节点 N 的高度;
- 更新节点 tmp 的高度。
static avl_node_t* LL(avl_node_t* node)
{
avl_node_t* temp = node->left_child;
node->left_child = temp->right_child;
if(NULL != temp->right_child) node->left_child->parent = node;
temp->parent = node->parent;
temp->right_child = node;
node->parent = temp;
node->depth = HEIGHT(node); // 更新节点高度,顺序不能换
temp->depth = HEIGHT(temp);
return temp;
}
2.2. RR 型
- 简单的
RR
型旋转,依次插入5、6、7 时如下图所示
如上图所示,当插入节点 7 时,导致节点 5 失衡,此时节点 5 左子树的高度小于其右子树的高度,且节点 5 的右孩子(节点 6)的左子树高度小于右子树高度,所以进行RR
型旋转。
- 复杂的
RR
型旋转
依次插入5、4、7、6、8、9 时如下图所示:
如上图所示,当插入节点 9 时,导致节点 5 失衡,此时节点 5 左子树的高度小于其右子树的高度,且节点 5 的右孩子(节点 7)的左子树高度小于右子树高度,所以进行RR
型旋转。 RR
型旋转步骤
- 假设失衡节点为节点 N,先暂存节点 N 的右孩子为节点 tmp;
- 令节点 N 的右孩子为节点 tmp 的左孩子;
- 令节点 tmp 的左孩子为节点 N;
- 更新节点 N 的高度;
- 更新节点 tmp 的高度。
static avl_node_t* RR(avl_node_t* node)
{
avl_node_t* temp = node->right_child;
node->right_child = temp->left_child;
if(NULL != temp->left_child) node->right_child->parent = node;
temp->parent = node->parent;
temp->left_child = node;
node->parent = temp;
node->depth = HEIGHT(node);
temp->depth = HEIGHT(temp);
return temp;
}
2.3. LR 型
依次插入 5、3、4 时,如下图所示:
如上图所示:当插入节点 4 时,导致节点 5 失衡,节点 5 的左子树高度不小于右子树高度,且节点 4 的左孩子(节点 3)的左节点高度小于其右节点高度,所以进行LR
型旋转。
LR
型旋转步骤
- 假设失衡节点为节点 N,先对节点 N 的左孩子进行
RR
型旋转;- 令节点 N 的左孩子为步骤 1 中调整后的根节点;
- 对节点 N 进行
LL
型旋转。
static avl_node_t* LR(avl_node_t* node)
{
node->left_child = RR(node->left_child);
return LL(node);
}
2.4. RL型
依次插入 5、7、6 时,如下图所示:
如上图所示:当插入节点 6 时,导致节点 5 失衡,节点 5 的左子树高度小于右子树高度,且节点 4 的右孩子(节点 7)的左节点高度不小于其右节点高度,所以进行LR
型旋转。
LR
型旋转步骤
- 假设失衡节点为节点 N,先对节点 N 的左孩子进行
RR
型旋转;- 令节点 N 的左孩子为步骤 1 中调整后的根节点;
- 对节点 N 进行
LL
型旋转。
static avl_node_t* LR(avl_node_t* node)
{
node->left_child = RR(node->left_child);
return LL(node);
}
三、AVL树的相关操作
3.1. 增加节点
从根节点开始,对比要插入的的节点键值和当前节点键值的大小,若小于当前节点键值则向左子树再继续对比,若大于当前节点键值则向右子树再继续对比,这样一直找到一个空节点存放要插入的节点,若对比到要插入的键值与当前比较的节点键值相同则退出插入。最后从插入节点的父节点开始,依次向上调整每个节点使 AVL 达到平衡状态,直到根节点结束。
3.2. 查询节点
查询节点比较简单,从根节点开始,不断比较需要查询的键值和当前键值的大小,若查询的键值小于当前节点键值,则往左子树查找,若大于当前键值则往右子树查找,若等于当前键值则返回查找到的节点。
static avl_node_t* query_by_key(avl_tree_t *tree, int key)
{
if(NULL == tree) return NULL;
AVL_LOG_DEBUG("Query key %d", key);
avl_tree_private_t* _this = get_private_member(tree);
avl_node_t* p = _this->m_root;
while(NULL != p)
{
if(key > p->key)
{
p = p->right_child;
}
else if(key < p->key)
{
p = p->left_child;
}
else break;
}
return p;
}
3.3. 删除节点
删除节点时需要传入指定的键值,然后查询到键值对应的节点,我们先称为 node 节点。当该节点存在左子树或者右子树的时候,按如下规则删除节点;
- 若左子树高度大于右子树,则取 node 节点左子树中最大的那个节点来替换 node 节点;
- 否则,取 node 节点右子树中最小的那个节点来替换 node 节点;
- 从替换 node 节点的那个节点原来的父节点开始,依次向上调整到根节点,使 AVL 树达到平衡。
假设我们现在有 AVL树的节点分别是 10、6、12、3、7、11、13、2、5、8、14、4,现在我们要删除节点 6,则删除过程如下图所示:
如上图所示,我们要删除节点 6,可看到节点6的左子树高度大于右子树高度,则取左子树中最大的节点(节点5)来替代节点 6,首先令节点 5 的父节点(节点 3)的右孩子等于节点 5 的左孩子(节点 4),然后节点 5 的左孩子等于节点 6 的左孩子, 节点 5 的右孩子等于节点 6 的右孩子,节点 5 的父节点等于节点 6 的父节点。然后从节点 5 原来的父节点(节点 4)开始向上依次调整至根节点,使 AVL树达到平衡。
3.4. 遍历节点
遍历节点分为前序遍历、中序遍历和后序遍历,由于遍历相对比较简单,这边以前序遍历为例讲解。
static void preorder (avl_node_t* node, void( *visit)(void* e) )
{
if (NULL == node) return;
visit(node->element); // 访问结点
preorder(node->left_child, visit); // 遍历左子树
preorder(node->right_child, visit);// 遍历右子树
}
上述代码中使用递归的方式,先访问根节点,然后访问左子树,最后访问右子树,这称为前序遍历。
3.5. 清空节点
清空节点是也是选择使用递归的方式,进行后序遍历清除节点。
static void avl_tree_node_clear(avl_tree_t* tree, avl_node_t* node)
{
if(NULL == node) return;
avl_tree_node_clear(tree, node->left_child);
avl_tree_node_clear(tree, node->right_child);
avl_tree_free_node(tree, node);
}
四、完整代码
AVLTree.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "AVLTree.h"
#define DEBUG_LOG 0
#define AVL_LOG_DEBUG(fmt, ...) \
do{ \
if(DEBUG_LOG) \
{\
printf("%s at %d " fmt "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);\
}\
}while(0);
typedef struct _avl_node avl_node_t;
typedef struct _avl_tree_private avl_tree_private_t;
struct _avl_node
{
avl_node_t *parent; // 父节点
avl_node_t *left_child; // 左孩子
avl_node_t *right_child; // 右孩子
void *element; // 节点保存的元素
int depth; // 当前节点的高度
int key; // 键值
};
struct _avl_tree_private
{
avl_node_t *m_root;
int m_element_size;
int m_node_cnt;
bool m_is_thread_safe;
pthread_mutex_t m_tree_mutex;
};
#define MAX(a, b) (int)((a) > (b) ? (a) : (b))
// 获取节点高度
#define HEIGHT(node) ((NULL == (node)) ? 0 : (MAX((NULL != node->left_child ? node->left_child->depth : 0), (NULL != node->right_child ? node->right_child->depth : 0) ) + 1))
#define ABS(a) ( (a) > 0 ? (a) : (- (a)))
#define INIT_KEY (int)(-1)
/*
@func:
获取私有成员变量
@para:
tree : 树指针
@return:
avl_tree_private_t* : 私有成员变量结构体指针
*/
static avl_tree_private_t* get_private_member(avl_tree_t* tree)
{
if(NULL == tree) return NULL;
return (avl_tree_private_t*)tree->_private_;
}
/*
@func:
线程锁, 上锁/解锁
@para:
tree : 树指针
@return:
None
@note:
若用户代码结构不会造成冲突可不使用
*/
static void avl_tree_lock(avl_tree_t* tree)
{
avl_tree_private_t* _this = get_private_member(tree);
if(_this->m_is_thread_safe)
pthread_mutex_lock(&_this->m_tree_mutex);
}
static void avl_tree_unlock(avl_tree_t* tree)
{
avl_tree_private_t* _this = get_private_member(tree);
if(_this->m_is_thread_safe)
pthread_mutex_unlock(&_this->m_tree_mutex);
}
/*
@func:
添加到目标节点的 左/右 孩子
@para:
node : 要添加的节点
p : 目标节点
@return:
None
*/
static void add_to_left(avl_node_t* node, avl_node_t* p)
{
p->left_child = node;
node->parent = p;
node->left_child = node->right_child = NULL;
node->depth = 1;
}
static void add_to_right(avl_node_t* node, avl_node_t* p)
{
p->right_child = node;
node->parent = p;
node->left_child = node->right_child = NULL;
node->depth = 1;
}
/*
@func:
LL / RR / LR / RL 型旋转
@para:
node : 要调整的节点
@return:
avl_node_t* : 调整后的根节点(此根节点并非树的根节点,而是替换被调整那个节点的位置的节点)
@note:
算法说明:左左旋转(LL)
+---+ +---+
node ---> | 5 | temp ---> | 3 |
+---+ +---+
/ \ / \
/ \ / \
/ \ / \
+---+ +---+ +---+ +---+
temp ---> | 3 | | 6 | ===> | 2 | | 5 | <--- node
+---+ +---+ +---+ +---+
/ \ / / \
/ \ / /
/ \ / / \
+---+ +---+ +---+ +---+ +---+
| 2 | | 4 | | 1 | | 4 | | 6 |
+---+ +---+ +---+ +---+ +---+
/
/
/
+---+
| 1 |
+---+
*/
static avl_node_t* LL(avl_node_t* node)
{
//AVL_LOG_DEBUG("LL %d", *((char*)(node->element) + 4));
avl_node_t* temp = node->left_child;
node->left_child = temp->right_child;
if(NULL != temp->right_child) node->left_child->parent = node;
temp->parent = node->parent;
temp->right_child = node;
node->parent = temp;
node->depth = HEIGHT(node); // 顺序不能换
temp->depth = HEIGHT(temp);
return temp;
}
static avl_node_t* RR(avl_node_t* node)
{
//AVL_LOG_DEBUG("RR %d", *((char*)(node->element) + 4));
avl_node_t* temp = node->right_child;
node->right_child = temp->left_child;
if(NULL != temp->left_child) node->right_child->parent = node;
temp->parent = node->parent;
temp->left_child = node;
node->parent = temp;
node->depth = HEIGHT(node);
temp->depth = HEIGHT(temp);
return temp;
}
static avl_node_t* RL(avl_node_t* node)
{
node->right_child = LL(node->right_child);
return RR(node);
}
static avl_node_t* LR(avl_node_t* node)
{
node->left_child = RR(node->left_child);
return LL(node);
}
/*
@func:
调整树
@para:
node : 要调整的节点
@return:
avl_node_t* : 调整后的根节点(此根节点并非树的根节点,而是替换被调整那个节点的位置的节点)
@note:
None.
*/
static avl_node_t* avl_tree_adjust(avl_node_t* node)
{
if (ABS(HEIGHT(node->left_child) - HEIGHT(node->right_child)) < 2)
return node;
if (HEIGHT(node->left_child) > HEIGHT(node->right_child))
{
if (HEIGHT(node->left_child->left_child) > HEIGHT(node->left_child->right_child))
{
return LL(node);
}
else
{
return LR(node);
}
}
else
{
if (HEIGHT(node->right_child->left_child) > HEIGHT(node->right_child->right_child))
{
return RL(node);
}
else
{
return RR(node);
}
}
}
/*
@func:
释放节点内存
@para:
tree : 树指针
node : 要释放内存的节点
@return:
int : 0 成功, -1 失败
@note:
None.
*/
static int avl_tree_free_node(avl_tree_t* tree, avl_node_t* node)
{
if(NULL == node || NULL == tree) return -1;
if(NULL != tree->pf_free_element)
tree->pf_free_element(node->element);
if(NULL != node->element)
{
free(node->element);
node->element = NULL;
}
free(node);
node = NULL;
return 0;
}
/*
@func:
创建一个节点
@para:
tree : 树指针
@return:
avl_node_t* : 创建的节点
@note:
None.
*/
static avl_node_t* avl_tree_create_node(avl_tree_t* tree)
{
if(NULL == tree) return NULL;
avl_tree_private_t* _this = get_private_member(tree);
avl_node_t* node = (avl_node_t*)malloc(sizeof(avl_node_t));
if(NULL == node)
{
AVL_LOG_DEBUG("[ERROR]:node malloc");
return NULL;
}
node->element = malloc(_this->m_element_size);
node->key = INIT_KEY;
return node;
}
/*
@func:
增加节点
@para:
tree : 树指针
node : 要增加的节点
@return:
int : -1 树指针为空, -2 创建节点失败, -3 重复插入
@note:
None.
*/
static int avl_tree_add(avl_tree_t *tree, void *ele)
{
if(tree == NULL) return -1;
avl_node_t* node = avl_tree_create_node(tree);
if(NULL == node) return -2;
avl_tree_private_t* _this = get_private_member(tree);
AVL_LOG_DEBUG("Add key[%d]", tree->pf_hash(ele));
memcpy(node->element, ele, _this->m_element_size);
int key = tree->pf_hash(node->element);
if(INIT_KEY == node->key)
node->key = key;
avl_tree_lock(tree);
if(NULL == _this->m_root) // 添加第一个节点
{
node->depth = 1;
node->left_child = node->right_child = node->parent = NULL;
_this->m_root = node;
_this->m_node_cnt = 1;
avl_tree_unlock(tree);
return 0;
}
avl_node_t* p = _this->m_root;
while(NULL != p)
{
if(key < p->key) // 添加到左子树
{
if(NULL == p->left_child)
{
add_to_left(node, p);
break;
}
else
{
p = p->left_child;
}
}
else if(key > p->key) // 添加到右子树
{
if(NULL == p->right_child)
{
add_to_right(node, p);
break;
}
else
{
p = p->right_child;
}
}
else
{
AVL_LOG_DEBUG("Element repetition");
avl_tree_free_node(tree, node);
avl_tree_unlock(tree);
return -3; // 重复
}
}
while(NULL != p)
{
p->depth = HEIGHT(p);
if(NULL == p->parent) // 调整到根节点
{
_this->m_root = avl_tree_adjust(p);
break;
}
else
{
if(p == p->parent->left_child)
{
p = p->parent;
p->left_child = avl_tree_adjust(p->left_child);
}
else
{
p = p->parent;
p->right_child = avl_tree_adjust(p->right_child);
}
}
}
_this->m_node_cnt++;
avl_tree_unlock(tree);
return 0;
}
/*
@func:
通过键值查找节点
@para:
tree : 树指针
key : 节点元素对应的键值
@return:
avl_node_t* : 查找到的节点
@note:
None.
*/
static avl_node_t* query_by_key(avl_tree_t *tree, int key)
{
if(NULL == tree) return NULL;
AVL_LOG_DEBUG("Query key %d", key);
avl_tree_private_t* _this = get_private_member(tree);
avl_node_t* p = _this->m_root;
while(NULL != p)
{
if(key > p->key)
{
p = p->right_child;
}
else if(key < p->key)
{
p = p->left_child;
}
else break;
}
return p;
}
static void* avl_tree_query_by_key(avl_tree_t *tree, int key)
{
avl_node_t* node = query_by_key(tree, key);
if(NULL == node) return NULL;
return node->element;
}
/*
@func:
通过元素查找节点
@para:
tree : 树指针
ele : 要查找的元素
@return:
avl_node_t* : 查找到的节点
@note:
None.
*/
static avl_node_t* avl_tree_query_by_element(avl_tree_t *tree, void* ele)
{
if(NULL == tree || NULL == ele) return NULL;
avl_tree_private_t* _this = get_private_member(tree);
int key = tree->pf_hash(ele);
avl_node_t* p = _this->m_root;
while(NULL != p)
{
if(key > p->key)
{
p = p->right_child;
}
else if(key < p->key)
{
p = p->left_child;
}
else break;
}
return p;
}
/*
@func:
通过键值删除节点
@para:
tree : 树指针
key : 节点元素对应的键值
@return:
int : 0 成功 -1 失败
@note:
None.
*/
static int avl_tree_del_by_key(avl_tree_t* tree, int key)
{
if(NULL == tree) return -1;
avl_tree_private_t* _this = get_private_member(tree);
avl_node_t* node = query_by_key(tree, key);
if(NULL == node) return -1;
avl_tree_lock(tree);
_this->m_node_cnt--;
avl_node_t *p = node->parent; // 先保存删除节点的父节点,方便后面调整树
avl_node_t *temp = NULL; // 替换 node 节点的节点
/*
当该节点存在左子树或者右子树的时候,比较两边的高度;
若左子树高度大于右子树,则取 node 节点左子树中最大的那个节点来替换 node 节点
否则,取 node 节点右子树中最小的那个节点来替换 node 节点
*/
if (NULL != node->left_child || NULL != node->right_child)
{
if (HEIGHT(node->left_child) > HEIGHT(node->right_child))
{
temp = node->left_child;
while (NULL != temp->right_child) // 找到 node 左子树中最大的节点
{
temp = temp->right_child;
}
if (temp != node->left_child)
{
p = temp->parent;
temp->parent->right_child = temp->left_child;
if (NULL != temp->left_child)
temp->left_child->parent = temp->parent;
temp->left_child = node->left_child;
temp->left_child->parent = temp;
}
temp->right_child = node->right_child;
if (NULL != temp->right_child)
temp->right_child->parent = temp;
}
else
{
temp = node->right_child;
while (NULL != temp->left_child)
{
temp = temp->left_child;
}
if (temp != node->right_child)
{
p = temp->parent;
temp->parent->left_child = temp->right_child;
if (NULL != temp->right_child)
temp->right_child->parent = temp->parent;
temp->right_child = node->right_child;
temp->right_child->parent = temp;
}
temp->parent = node->parent;
temp->left_child = node->left_child;
if (NULL != temp->left_child)
temp->left_child->parent = temp;
}
temp->parent = node->parent;
temp->depth = HEIGHT(temp);
}
if (NULL != node->parent)
{
if (node == node->parent->left_child)
node->parent->left_child = temp;
else if (node == node->parent->right_child)
node->parent->right_child = temp;
}
// 如果是删除的根节点,需要更新下根节点,否则会导致根节点为NULL
if(NULL == p)
_this->m_root = temp;
while(NULL != p)
{
p->depth = HEIGHT(p);
if(NULL == p->parent)
{
// 找到根节点
_this->m_root = avl_tree_adjust(p);
break;
}
else
{
if(p == p->parent->left_child)
{
p = p->parent;
p->left_child = avl_tree_adjust(p->left_child);
}
else
{
p = p->parent;
p->right_child = avl_tree_adjust(p->right_child);
}
}
}
avl_tree_free_node(tree, node);
avl_tree_unlock(tree);
return 0;
}
/*
@func:
通过元素删除节点
@para:
tree : 树指针
ele : 节点的元素
@return:
int : 0 成功 -1 失败
@note:
None.
*/
static int avl_tree_del_by_element(avl_tree_t* tree, void* ele)
{
avl_node_t* node= avl_tree_query_by_element(tree, ele);
if(NULL == node) return -1;
return avl_tree_del_by_key(tree, node->key);
}
/*
@func:
前序遍历
@para:
tree : 树指针
visit : 遍历时对每个元素执行的操作
@return:
None
*/
static void preorder (avl_node_t* node, void( *visit)(void* e) )
{
if (NULL == node) return;
visit(node->element); // 访问结点
preorder(node->left_child, visit); // 遍历左子树
preorder(node->right_child, visit);// 遍历右子树
}
static void avl_tree_preorder(avl_tree_t* tree, void( *visit)(void* e))
{
avl_tree_private_t *_this = get_private_member(tree);
preorder(_this->m_root, visit);
}
/*
@func:
获取树节点的数量
@para:
tree : 树指针
@return:
int : 树节点的数量
@note:
None.
*/
static int avl_tree_size(avl_tree_t* tree)
{
avl_tree_private_t* _this = get_private_member(tree);
return _this->m_node_cnt;
}
/*
@func:
清除目标节点以及其全部子树包含的节点
@para:
tree : 树指针
node : 节点的元素
@return:
int : 0 成功 -1 失败
@note:
None.
*/
static void avl_tree_node_clear(avl_tree_t* tree, avl_node_t* node)
{
if(NULL == node) return;
avl_tree_node_clear(tree, node->left_child);
avl_tree_node_clear(tree, node->right_child);
avl_tree_free_node(tree, node);
}
/*
@func:
清除树的全部节点
@para:
tree : 树指针
@return:
None.
@note:
None.
*/
static void avl_tree_clear(avl_tree_t *tree)
{
avl_tree_private_t* _this = get_private_member(tree);
avl_tree_node_clear(tree, _this->m_root);
_this->m_node_cnt = 0;
}
/*
@func:
销毁树
@para:
tree : 树指针
@return:
None.
@note:
None.
*/
static void avl_tree_destory(avl_tree_t** tree)
{
avl_tree_t* _this = *tree;
if(NULL == _this) return;
if(_this->size(_this) > 0)
{
_this->clear_node(_this);
}
if(_this->_private_)
{
free(_this->_private_);
_this->_private_ = NULL;
}
if(_this)
{
free(_this);
_this = NULL;
}
}
/*
@func:
创建一颗平衡二叉树
@para:
element_size : 节点保存元素的大小,单位字节
pf_hash_func ; 从节点元素获得键值 key 的方法,由用户提供
pf_free_element_func : 若节点元素不包含额外的动态内存, 此参数可传 NULL;
若节点包含的元素中还包含额外的动态内存,用户需传入此函数以正确释放内存
thread_safe : 是否启用线程安全,若用户保证不会涉及冲突,可关闭线程安全功能
@return:
avl_tree_t* : 创建平衡二叉树的指针
*/
avl_tree_t* avl_tree_create(int element_size, int (*pf_hash_func)(void *) ,int (*pf_free_element_func)(void *), bool thread_safe)
{
if(NULL == pf_hash_func)
return NULL;
avl_tree_t *tree = (avl_tree_t *)malloc(sizeof(avl_tree_t));
memset(tree, 0, sizeof(avl_tree_t));
avl_tree_private_t *private_member = (avl_tree_private_t *)malloc(sizeof(avl_tree_private_t));
private_member->m_root = NULL;
private_member->m_element_size = element_size;
private_member->m_is_thread_safe = thread_safe;
pthread_mutex_init(&private_member->m_tree_mutex, NULL);
tree->_this = tree;
tree->_private_ = (void *)private_member;
tree->pf_hash = pf_hash_func;
tree->pf_free_element = pf_free_element_func;
tree->add = avl_tree_add;
tree->query_by_key = avl_tree_query_by_key;
tree->preorder = avl_tree_preorder;
tree->size = avl_tree_size;
tree->del_node_by_key = avl_tree_del_by_key;
tree->del_node_by_element = avl_tree_del_by_element;
tree->clear_node = avl_tree_clear;
tree->destory = avl_tree_destory;
return tree;
}
AVLTree.h
#ifndef _AVL_TREE_H_
#define _AVL_TREE_H_
#include <stdbool.h>
#include <pthread.h>
typedef struct _avl_tree avl_tree_t;
struct _avl_tree
{
avl_tree_t *_this;
void *_private_; // 私有成员
int (*pf_hash)(void *); //用户提供的 hash 函数
int (*pf_free_element)(void *ele); // 用户提供的节点元素中保存的动态内存的释放方法
/*
@func:
增加节点
@para:
tree : 树指针
node : 要增加的节点
@return:
int : -1 树指针为空, -2 创建节点失败, -3 重复插入
@note:
None.
*/
int (*add)(avl_tree_t *tree, void *node);
/*
@func:
通过键值删除节点
@para:
tree : 树指针
key : 节点元素对应的键值
@return:
int : 0 成功 -1 失败
@note:
None.
*/
int (*del_node_by_key)(avl_tree_t* tree, int key);
/*
@func:
通过元素删除节点
@para:
tree : 树指针
ele : 节点的元素
@return:
int : 0 成功 -1 失败
@note:
None.
*/
int (*del_node_by_element)(avl_tree_t* tree, void *element);
/*
@func:
通过键值查找节点
@para:
tree : 树指针
key : 节点元素对应的键值
@return:
avl_node_t* : 查找到的节点
@note:
None.
*/
void* (*query_by_key)(avl_tree_t *tree, int key);
/*
@func:
前序遍历
@para:
tree : 树指针
visit : 遍历时对每个元素执行的操作
@return:
None
*/
void (*preorder)(avl_tree_t* tree, void( *visit)(void* ele));
/*
@func:
获取树节点的数量
@para:
tree : 树指针
@return:
int : 树节点的数量
@note:
None.
*/
int (*size)(avl_tree_t* tree);
/*
@func:
清除树的全部节点
@para:
tree : 树指针
@return:
None.
@note:
None.
*/
void (*clear_node)(avl_tree_t *tree);
/*
@func:
销毁树
@para:
tree : 树指针
@return:
None.
@note:
None.
*/
void (*destory)(avl_tree_t** tree);
};
/*
@func:
创建一颗平衡二叉树
@para:
element_size : 节点保存元素的大小,单位字节
pf_hash_func ; 从节点元素获得键值 key 的方法,由用户提供
pf_free_element_func : 若节点元素不包含额外的动态内存, 此参数可传 NULL;若节点包含的元素中还包含额外的动态内存,用户需传入此函数以正确释放内存
thread_safe : 是否启用线程安全,若用户保证不会涉及冲突,可关闭线程安全功能
@return:
avl_tree_t* : 创建平衡二叉树的指针
*/
extern avl_tree_t* avl_tree_create(int element_size, int (*pf_hash_func)(void *), int (*pf_free_element_func)(void *), bool thread_safe);
#endif /* end #ifndef _AVL_TREE_H_ */
avl_test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "AVLTree.h"
#define AVL_TEST_DEBUG(fmt, ...) \
do{ \
if(1) \
{\
printf("%s at %d " fmt "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);\
}\
}while(0);
typedef struct
{
void *record_data;
int key;
}record_data_t;
static int get_element_key(void *data)
{
// 节点元素的释放在 avl 里执行
if(NULL == data) return -1;
return ((record_data_t*)data)->key;
}
static int free_element_data(void *data)
{
if(NULL == data)
{
AVL_TEST_DEBUG("free element error data null");
return -1;
}
record_data_t* ele = (record_data_t*)data;
if(NULL != ele->record_data)
{
//AVL_TEST_DEBUG("free [%d]%s", ele->key, (char *)ele->record_data);
free(ele->record_data);
ele->record_data = NULL;
}
return 0;
}
void print_data(void *data)
{
if(NULL == data)
{
AVL_TEST_DEBUG("data null");
return;
}
record_data_t *record = (record_data_t*)data;
int out;
sscanf((char *)record->record_data, "node%d", &out);
AVL_TEST_DEBUG("[%d]----------------->[%s]\r\n", record->key, (char *)record->record_data);
if(out != record->key)
{
exit(-1);
}
}
static record_data_t create_record_data(char* data, int key, int malloc_size)
{
record_data_t ele;
memset(&ele, 0, sizeof(record_data_t));
ele.record_data = malloc(malloc_size);
memset(ele.record_data, 0, malloc_size);
memcpy(ele.record_data, data, strlen(data));
ele.key = key;
return ele;
}
int process(void)
{
avl_tree_t* tree = avl_tree_create(sizeof(record_data_t), get_element_key, free_element_data, 0);
if(NULL == tree)
{
AVL_TEST_DEBUG("create tree error!");
return -1;
}
srand(time(NULL));
for(int i = 0 ; i < 40; ++i)
{
char node_num[16] = {0};
int num = rand()%100;
sprintf(node_num, "node%d", num);
record_data_t ele = create_record_data(node_num, num, 10);
tree->add(tree->_this, &ele);
}
AVL_TEST_DEBUG("tree size[%d]", tree->size(tree->_this));
tree->preorder(tree->_this, print_data);
AVL_TEST_DEBUG("clear");
tree->clear_node(tree->_this);
tree->destory(&(tree->_this));
return 0;
}
int main()
{
while(1)
{
process();
usleep(200);
}
}
五、小结
AVL 树的介绍就到这里了,文中涉及代码为本人编写,未经严格测试,仅做参考。另外若有错误之处望不吝赐教。下一篇将介绍一个 AVL 树的小应用——简单文件数据库的实现。