C 语言实现 AVL 树

一、AVL 树简介

     AVL树 是平衡二叉树,其具有如下几个性质:

  1. 必须是二叉树;
  2. 必须是一颗空树或者其左右子树的高度之差的绝对值不超过 1。
  3. 对于每个节点,其左孩子比这个节点小,右孩子比这个节点大。

    平衡二叉树的作用主要是为了避免普通二叉查找树在极端情况下(全部节点只有左孩子或者全部节点只有右孩子)会变成链表那样,在操作的时候影响性能。

二、AVL树自平衡

    判断 AVL树 失衡形状时,先找出失衡节点,当失衡节点的左子树高度大于右子树的时候,记为 L,否则记为R,若左子树的高度大于右子树,再判断失衡节点的左孩子的左子树与右子树的关系,若失衡节点的左孩子的左子树高度大于失衡节点的左子树的右子树,则记为 LL型,否则记为LR型;同理,若失衡节点的右孩子高度大于左子树的高度时,可根据失衡节点右孩子的左右子树高度分别判断为RR型 和 RL型。
判断AVL树旋转类型流程图

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型旋转步骤
  1. 假设失衡节点为节点 N,先暂存节点 N 的左孩子为节点 tmp;
  2. 令节点 N 的左孩子为节点 tmp 的右孩子;
  3. 令节点 tmp 的右孩子为节点 N;
  4. 更新节点 N 的高度;
  5. 更新节点 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型旋转步骤
  1. 假设失衡节点为节点 N,先暂存节点 N 的右孩子为节点 tmp;
  2. 令节点 N 的右孩子为节点 tmp 的左孩子;
  3. 令节点 tmp 的左孩子为节点 N;
  4. 更新节点 N 的高度;
  5. 更新节点 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型旋转步骤
  1. 假设失衡节点为节点 N,先对节点 N 的左孩子进行RR型旋转;
  2. 令节点 N 的左孩子为步骤 1 中调整后的根节点;
  3. 对节点 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型旋转步骤
  1. 假设失衡节点为节点 N,先对节点 N 的左孩子进行RR型旋转;
  2. 令节点 N 的左孩子为步骤 1 中调整后的根节点;
  3. 对节点 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 树的小应用——简单文件数据库的实现。

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AVL树是一种平衡二叉树C语言中可以通过结构体和指针来实现AVL树。下面是一个简单的AVL树实现示例,包括AVL树的创建、插入、删除和遍历操作。 ```c #include <stdio.h> #include <stdlib.h> // 定义AVL树节点结构体 struct node { int data; int height; struct node *left; struct node *right; }; // 获取节点高度 int get_height(struct node *root) { if (!root) { return -1; } else { return root->height; } } // 获取节点平衡因子 int get_balance_factor(struct node *root) { if (!root) { return 0; } else { return get_height(root->left) - get_height(root->right); } } // 左旋转 struct node* left_rotate(struct node *root) { struct node *new_root; new_root = root->right; root->right = new_root->left; new_root->left = root; root->height = 1 + (get_height(root->left) > get_height(root->right) ? get_height(root->left) : get_height(root->right)); new_root->height = 1 + (get_height(new_root->left) > get_height(new_root->right) ? get_height(new_root->left) : get_height(new_root->right)); return new_root; } // 右旋转 struct node* right_rotate(struct node *root) { struct node *new_root; new_root = root->left; root->left = new_root->right; new_root->right = root; root->height = 1 + (get_height(root->left) > get_height(root->right) ? get_height(root->left) : get_height(root->right)); new_root->height = 1 + (get_height(new_root->left) > get_height(new_root->right) ? get_height(new_root->left) : get_height(new_root->right)); return new_root; } // 创建AVL树 struct node* create_avl_tree() { struct node *root; int data; printf("请输入根节点的数据:"); scanf("%d", &data); root = (struct node*) malloc(sizeof(struct node)); if (!root) { printf("内存分配失败\n"); exit(1); } root->data = data; root->height = 0; root->left = NULL; root->right = NULL; return root; } // 插入节点 struct node* insert_node(struct node *root, int data) { if (!root) { root = (struct node*) malloc(sizeof(struct node)); if (!root) { printf("内存分配失败\n"); exit(1); } root->data = data; root->height = 0; root->left = NULL; root->right = NULL; } else if (data < root->data) { root->left = insert_node(root->left, data); if (get_balance_factor(root) == 2) { if (get_balance_factor(root->left) == 1) { root = right_rotate(root); } else if (get_balance_factor(root->left) == -1) { root->left = left_rotate(root->left); root = right_rotate(root); } } } else if (data > root->data) { root->right = insert_node(root->right, data); if (get_balance_factor(root) == -2) { if (get_balance_factor(root->right) == -1) { root = left_rotate(root); } else if (get_balance_factor(root->right) == 1) { root->right = right_rotate(root->right); root = left_rotate(root); } } } else { printf("节点已存在\n"); } root->height = 1 + (get_height(root->left) > get_height(root->right) ? get_height(root->left) : get_height(root->right)); return root; } // 删除节点 struct node* delete_node(struct node *root, int data) { struct node *p; if (!root) { printf("节点不存在\n"); } else if (data < root->data) { root->left = delete_node(root->left, data); if (get_balance_factor(root) == -2) { if (get_balance_factor(root->right) == -1) { root = left_rotate(root); } else if (get_balance_factor(root->right) == 1) { root->right = right_rotate(root->right); root = left_rotate(root); } } } else if (data > root->data) { root->right = delete_node(root->right, data); if (get_balance_factor(root) == 2) { if (get_balance_factor(root->left) == 1) { root = right_rotate(root); } else if (get_balance

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值