`
xitonga
  • 浏览: 583897 次
文章分类
社区版块
存档分类
最新评论

算法导论 之 平衡二叉树 - 创建、插入、查询、销毁 - 递归[C语言]

 
阅读更多

1 引言


构造二叉排序树过程中,即使输入相同的关键字组合,但关键字顺序不一致时,产生的也不是不同形态的二叉排序树,其插入、查找、删除的性能差别很大(图1所示),如:
①、当组成的二叉排序树的形态为单分支树时,其平均查找时间为(N+1)/2,最差查找时间为N.
②、当组成的二叉排序树的形态为平衡二叉树时,其插入、删除、平均查找、最差查找时间均为log2@N[以2为底数,以N为对数].

大家可以通过以下图形对时间变化的趋势有一个大概的印象:


图1 变化趋势对比图

由图的变化趋势可知,当N逐渐增大时,时间相差的倍数越来越大[如:当N=2^32时,y = N/2 = 2^31,而y = log2@N = 2^5, 其性能差异可想而知]。因此,为了提高对二叉排序树的操作性能,很有必要在构造二叉树排序树时,进行平衡化处理,将其调整为一棵平衡二叉树。


2 平衡过程


平衡二叉树[Balanced Binary Tree]又称为AVL树,是二叉排序树的一种形式,其特点是:树中每个结点的左、右子树的深度之差的绝对值不超过1,即:|Hl - Hr| <= 1。

结点的平衡因子[Balance factor]:该结点的左子树深度Hl减去该结点的右子树的深度Hr。平衡二叉树所有结点的平衡因子的值只能为-1,0,1。

在构建平衡二叉树的过程中,插入一个新结点后,可能会造成平衡二叉树失去平衡。失去平衡后进行调整的规律可归纳为以下4种情况:[注:以下操作是平衡处理的核心,请认真分析总结]

2.1 LL型

当结点A的平衡因子为2(失衡),且其左子结点B的平衡因子为1时,则可判定为LL型失衡!
失衡场景:
新结点x插在左重结点A[A是离插入新结点x位置最近的左重结点]左孩子的左分支上,造成结点A失衡,如下图所示:[注:AR表示结点A的右子树,BL表示结点B的左子树,BR表示结点B的右子树]

图2 LL型
平衡过程:(如图3所示)
①、BA向右旋转90度:结点B替换结点A的位置
②、结点B的右孩子BR改为结点A的左孩子,把结点A作为结点B的右孩子

图3 LL型平衡结果

2.2 LR型

当结点A的平衡因子为2,且其左孩子结点B的平衡因子为-1时,则可判断为LR型 - 但C的平衡因子有2种情况:-1, 1。
失衡场景:结点C的平衡因子为1时
新结点x插在左重结点A[A是离插入新结点x位置最近的左重结点]左孩子的右孩子的左分支上,如下图所示:

图4 LR型
平衡过程:(如图5、6所示)
①、将CB向左旋转90度,把C的左孩子CL作为B的右孩子,再将B作为C的左孩子,C替代B的位置

图5 LR型平衡-左旋
②、将BCA向右旋转90度,把C的右孩子CR作为A的左孩子,将A作为C的右孩子,C替代A的位置

图6 LR型平衡-右旋

2.3 RR型

当结点A的平衡因子为-2,且其左子点B的平衡因子为-1时,则可判断为RR型。
失衡描述:
新结点x插在右重结点A[A是离插入新结点x位置最近的右重结点]右孩子的右分支上,如下图所示:

图7 RR型
平衡过程:(如图3所示)
①、AB向左旋转90度:结点B替换结点A的位置
②、把B的左孩子BR改为A的右孩子,把A作为B的左孩子

图8 RR型平衡结果-左旋

2.4 RL型

当结点A的平衡因子为-2,且其右孩子结点B的平衡因子为1时,则可判断为RL型 - 但C的平衡因子有2种情况:-1, 1。
失衡描述①:结点C的平衡因子为-1时
新结点x插在左重结点A[A是离插入新结点x位置最近的右重结点]孩子的左孩子的右分支上,如下图所示:

图9 RL型
平衡过程:(如图10、11所示)
①、将CB向右旋转90度:结点C替代结点B的位置,再把结点C的右孩子CR作为B的左孩子,再将B作为C的右孩子

图10 RL型平衡-右旋
②、将BCA向左旋转90度:结点C替代结点A的位置,把C的左孩子CL作为A的右孩子,将A作为C的左孩子

图11 RL型平衡结果-左旋


3 操作接口


3.1 结构定义

>结点结构定义:
/* 结点结构 */
typedef struct _avl_node_t
{
    struct _avl_node_t *parent; /* 父结点 */
    struct _avl_node_t *lchild; /* 左孩子 */
    struct _avl_node_t *rchild; /* 右孩子 */
    int key;                    /* 结点值: 如果想构造成通用的平衡二叉树,在此可使用void *类型 */
    int bf;                     /* 平衡因子 */
}avl_node_t;
代码1 结点结构
>树结构定义:
/* 树结构 */
typedef struct
{
    node_t *root;       /* 根结点 */
    /* 如果想构造成通用的平衡二叉树,可以在此增加一个比较函数指针,其类型为:
        typedef int (*cmp)(const void *s1, const void *s2)
            1. 当s1 < s2时: 返回值小于0
            2. 当s1 == s2时: 返回值等于0
            3. 当s1 > s2时: 返回值大于0 */
}avl_tree_t;
代码2 平衡二叉树结构
>错误码:可根据实际情况动态扩展
typedef enum
{
    AVL_SUCCESS                   /* 成功 */
    , AVL_FAILED = ~0x7FFFFFFF    /* 失败 */
    , AVL_NODE_EXIST              /* 结点存在 */
    , AVL_ERR_STACK               /* 栈异常 */
}AVL_RET_e;
代码3 返回值定义
>其他定义:
/* 平衡因子 */
#define AVL_RH    (-1)    /* 右高 */
#deifne AVL_EH    (0)     /* 等高 */
#define AVL_LH    (1)     /* 左高 */

#define AVL_MAX_DEPTH    (512) /* AVL栈的最大深度 */
/* BOOL类型 */
typedef int bool;
#define true (1)
#define false (0)


/* 设置node的左孩子结点 */
#define avl_set_lchild(node, lc) \
{ \
    (node)->lchild = (lc); \
    if(NULL != (lc)) \
    { \
        (lc)->parent = (node); \
    } \
}

/* 设置node的右孩子结点 */
#define avl_set_rchild(node, rc) \
{ \
    (node)->rchild = (rc); \
    if(NULL != (rc)) \
    { \
        (rc)->parent = (node); \
    } \
}

/* 替换父结点的孩子结点 */
#define avl_instead_child(tree, parent, old, _new) \
{ \
    if(NULL == parent) \
    { \
        (tree)->root = (_new); \
        if(NULL != (_new)) \
        { \
            (_new)->parent = NULL; \
        } \
    } \
    else if(parent->lchild == old) \
    { \
        avl_set_lchild(parent, _new); \
    } \
    else if(parent->rchild == old) \
    { \
        avl_set_rchild(parent, _new); \
    } \
}
代码4 其他定义

3.2 创建对象

增加创建平衡二叉树对象的接口可以有效的屏蔽平衡二叉树的成员变量的定义,使用者不必关心哪些参数需要设置或修改,只需知道参数接口便可正确使用。其代码实现如下:
/******************************************************************************
 **函数名称: avl_creat
 **功    能: 创建平衡二叉树对象(对外接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **输出参数: NONE
 **返    回: AVL_SUCCESS:成功 AVL_FAILED:失败
 **实现描述: 
 **注意事项: 
 **作    者: # Qifeng.zou # 2013.12.19 #
 ******************************************************************************/
int avl_creat(avl_tree_t **tree)
{
    *tree = (avl_tree_t *)calloc(1, sizeof(avl_tree_t));
    if(NULL == *tree)
    {
        return AVL_FAILED;
    }

    (*tree)->root = NULL;
    return AVL_SUCCESS;
}
代码5 创建平衡二叉树

3.3 插入结点

花了整整一天的时间进行的代码的编写和调试,终于完成了使用C语言实现平衡二叉树的插入处理,在测试过程中,竟然发现构造的二叉树形成了死循环,使用GDB怎么都跟不出来,最终还是通过assert(node == node->rchild->parent)找出了错误的代码!其代码如下所示:[可直接编译运行]
/******************************************************************************
 **函数名称: avl_insert
 **功    能: 插入新结点(对外接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 新结点
 **输出参数: NONE
 **返    回: AVL_SUCCESS:成功 AVL_NODE_EXIST:已存在 AVL_FAILED:失败
 **实现描述: 
 **     1. 当树的根结点为空时,则直接创建根结点,并赋值
 **     2. 当树的根结点不为空时,则调用_avl_insert()进行处理
 **注意事项: 
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
int avl_insert(avl_tree_t *tree, int key)
{
    bool taller = false;
    avl_node_t *node = tree->root;

    /* 如果为空树,则创建第一个结点 */
    if(NULL == node)
    {
        node = (node_t *)calloc(1, sizeof(node_t));
        if(NULL == node)
        {
            return AVL_FAILED;
        }
        node->parent = NULL;
        node->rchild = NULL;
        node->lchild = NULL;
        node->bf = AVL_EH;
        node->key = key;
        
        tree->root = node;
        return AVL_SUCCESS;
    }

    return _avl_insert(tree, node, key, &taller); /* 调用插入结点的接口 */
}
代码6 插入结点(对外接口)
/******************************************************************************
 **函数名称: _avl_insert
 **功    能: 插入新结点(内部接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 需在该结点的子树上插入key
 **     key: 需被插入的key
 **输出参数: 
 **     taller: 是否增高
 **返    回: AVL_SUCCESS:成功 AVL_NODE_EXIST:已存在 AVL_FAILED:失败
 **实现描述: 
 **     1. 当结点关键字等于key值时,结点已存在
 **     2. 当结点关键字小于key值时,插入右子树
 **     3. 当结点关键字大于key值时,插入左子树
 **注意事项: 
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
static int _avl_insert(avl_tree_t *tree, avl_node_t *node, int key, bool *taller)
{
    if(key == node->key)        /* 结点已存在 */
    {
        *taller = false;
        return AVL_NODE_EXIST;
    }
    else if(key > node->key)    /* 插入右子树 */
    {
        return avl_insert_right(tree, node, key, taller);
    }

    /* 插入左子树 */
    return avl_insert_left(tree, node, key, taller);
}
代码7 插入结点(内部接口)
/******************************************************************************
 **函数名称: avl_insert_right
 **功    能: 在node的右子树中插入新结点(内部接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 需在该结点的子树上插入key
 **     key: 需被插入的key
 **输出参数: 
 **     taller: 是否增高
 **返    回: AVL_SUCCESS:成功 AVL_NODE_EXIST:已存在 AVL_FAILED:失败
 **实现描述: 
 **注意事项: 
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
static int avl_insert_right(avl_tree_t *tree, avl_node_t *node, int key, bool *taller)
{
    int ret = -1;
    avl_node_t *add = NULL;
    
    if(NULL == node->rchild)
    {
        add = (node_t *)calloc(1, sizeof(node_t));
        if(NULL == add)
        {
            *taller = false;
            return AVL_FAILED;
        }

        add->lchild = NULL;
        add->rchild = NULL;
        add->parent = node;
        add->key = key;
        add->bf = AVL_EH;
        
        node->rchild = add;
        *taller = true;     /* node的高度增加了 */
    }
    else
    {
        ret = _avl_insert(tree, node->rchild, key, taller);
        if((AVL_SUCCESS != ret))
        {
            return ret;
        }
    }

    if(false == *taller)
    {
        return AVL_SUCCESS;
    }

    /* 右增高: 进行平衡化处理 */
    switch(node->bf)
    {
        case AVL_LH:    /* 左高: 右子树增高 不会导致失衡 */
        {
            node->bf = AVL_EH;
            *taller = false;
            return AVL_SUCCESS;
        }
        case AVL_EH:    /* 等高: 右子树增高 不会导致失衡 */
        {
            node->bf = AVL_RH;
            *taller = true;
            return AVL_SUCCESS;
        }
        case AVL_RH:    /* 右高: 右子树增高 导致失衡 */
        {
            avl_right_balance(tree, node);
            *taller = false;
            return AVL_SUCCESS;
        }
    }

    return AVL_FAILED;
}
代码8 插入右子树(内部接口)
/******************************************************************************
 **函数名称: avl_insert_left
 **功    能: 在node的左子树中插入新结点(内部接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 需在该结点的子树上插入key
 **     key: 需被插入的key
 **输出参数: 
 **     taller: 是否增高
 **返    回: AVL_SUCCESS:成功 AVL_NODE_EXIST:已存在 AVL_FAILED:失败
 **实现描述: 
 **注意事项: 
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
static int avl_insert_left(avl_tree_t *tree, avl_node_t *node, int key, bool *taller)
{
    int ret = -1;
    avl_node_t *add = NULL;
    
    if(NULL == node->lchild)
    {
        add = (node_t *)calloc(1, sizeof(node_t));
        if(NULL == add)
        {
            *taller = false;
            return AVL_FAILED;
        }

        add->lchild = NULL;
        add->rchild = NULL;
        add->parent = node;
        add->key = key;
        add->bf = AVL_EH;
        
        node->lchild = add;
        *taller = true;     /* node的高度增加了 */
    }
    else
    {
        ret = _avl_insert(tree, node->lchild, key, taller);
        if(AVL_SUCCESS != ret)
        {
            return ret;
        }
    }

    if(false == *taller)
    {
        return AVL_SUCCESS;
    }

    /* 左增高: 进行平衡化处理 */
    switch(node->bf)
    {
        case AVL_RH:    /* 右高: 左子树增高 不会导致失衡 */
        {
            node->bf = AVL_EH;
            *taller = false;
            return AVL_SUCCESS;
        }
        case AVL_EH:    /* 等高: 左子树增高 不会导致失衡 */
        {
            node->bf = AVL_LH;
            *taller = true;
            return AVL_SUCCESS;
        }
        case AVL_LH:    /* 左高: 左子树增高 导致失衡 */
        {
            avl_left_balance(tree, node);
            *taller = false;
            return AVL_SUCCESS;
        }
    }

    return AVL_FAILED;
}
代码9 插入左子树(内部接口)
/******************************************************************************
 **函数名称: avl_rr_balance
 **功    能: RR型平衡化处理 - 向左旋转(内部接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 右边失去平衡的结点
 **输出参数: NONE
 **返    回: AVL_SUCCESS:成功 AVL_FAILED:失败
 **实现描述: RR型
 **              A                  C
 **             / \                / \
 **            AL  C      ->      A  CR
 **               / \            / \   \
 **              CL CR          AL CL   X
 **                   \
 **                    X
 **              (1)                (2)
 ** 说明: 结点A是失衡结点,此时当结点C的平衡因子为-1时,可判断为RR型。
 **注意事项: 
 **     1. 图(1)中A表示右边失衡的结点 图(2)表示平衡处理的结果
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
static int avl_rr_balance(avl_tree_t *tree, avl_node_t *node)
{
    avl_node_t *rchild = node->rchild, *parent = node->parent;

    avl_set_rchild(node, rchild->lchild);
    node->bf = AVL_EH;

    avl_set_lchild(rchild, node);
    rchild->bf = AVL_EH;

    avl_instead_child(tree, parent, node, rchild);

    return AVL_SUCCESS;
}
代码10 RR型平衡化处理(内部接口)
/******************************************************************************
 **函数名称: avl_rl_balance
 **功    能: RL型平衡化处理 - 先向右旋转 再向左旋转(内部接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 右边失去平衡的结点
 **输出参数: NONE
 **返    回: AVL_SUCCESS:成功 AVL_FAILED:失败
 **实现描述: 
 ** 场景1: RL型
 **              A                    B
 **             / \                /    \
 **            AL  C      ->      A      C
 **               / \            / \    / \
 **              B  CR          AL BL  BR CR
 **             / \
 **            BL BR
 **              (1)                (2)
 ** 说明: 结点A是失衡结点,此时当结点C的平衡因子为1时,可判断为RL型。
 **       虽然此时结点B的平衡因子的值可能为:-1, 0, 1. 
 **       但旋转处理的方式是一致的,只是旋转之后的平衡因子不一致.
 **注意事项: 
 **     1. 图(1)中A表示右边失衡的结点 图(2)表示平衡处理的结果
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
int avl_rl_balance(avl_tree_t *tree, avl_node_t *node)
{
    avl_node_t *rchild = node->rchild,
        *parent = node->parent, *rlchild = NULL;
    
    rlchild = rchild->lchild;
    switch(rlchild->bf)
    {
        case AVL_LH:
        {
            node->bf = AVL_EH;
            rchild->bf = AVL_RH;
            rlchild->bf = AVL_EH;
            break;
        }
        case AVL_EH:
        {
            node->bf = AVL_EH;
            rchild->bf = AVL_EH;
            rlchild->bf = AVL_EH;
            break;
        }
        case AVL_RH:
        {
            node->bf = AVL_LH;
            rchild->bf = AVL_EH;
            rlchild->bf = AVL_EH;
            break;
        }
    }

    avl_set_lchild(rchild, rlchild->rchild);
    avl_set_rchild(rlchild, rchild); 
    avl_set_rchild(node, rlchild->lchild);
    avl_set_lchild(rlchild, node);

    avl_instead_child(tree, parent, node, rlchild);
    
    return AVL_SUCCESS;
}
代码11 RL型平衡化处理(内部接口)
/******************************************************************************
 **函数名称: avl_right_balance
 **功    能: 对右边失去平衡的结点进行平衡化处理(内部接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 右边失去平衡的结点
 **输出参数: NONE
 **返    回: AVL_SUCCESS:成功 AVL_FAILED:失败
 **实现描述: 
 ** 场景1: RR型
 **              A                  C
 **             / \                / \
 **            AL  C      ->      A  CR
 **               / \            / \   \
 **              CL CR          AL CL   X
 **                   \
 **                    X
 **              (1)                (2)
 ** 说明: 结点A是失衡结点,此时当结点C的平衡因子为-1时,可判断为RR型。
 ** 场景2: RL型
 **              A                    B
 **             / \                /    \
 **            AL  C      ->      A      C
 **               / \            / \    / \
 **              B  CR          AL BL  BR CR
 **             / \
 **            BL BR
 **              (1)                (2)
 ** 说明: 结点A是失衡结点,此时当结点C的平衡因子为1时,可判断为RL型。
 **       虽然此时结点B的平衡因子的值可能为:-1, 0, 1. 
 **       但旋转处理的方式是一致的,只是旋转之后的平衡因子不一致.
 **注意事项: 
 **     1. 图(1)中A表示右边失衡的结点 图(2)表示平衡处理的结果
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
static int avl_right_balance(avl_tree_t *tree, avl_node_t *node)
{
    avl_node_t *rchild = node->rchild;

    switch(rchild->bf)
    {
        case AVL_RH:    /* 场景1: RR型 - 向左旋转 */
        {
            return avl_rr_balance(tree, node);
        }
        case AVL_LH:    /* 场景2: RL型 - 先向右旋转 再向左旋转 */
        {
            return avl_rl_balance(tree, node);
        }
    }

    return AVL_FAILED;
}
代码12 RR型和RL平衡化处理(内部接口)
/******************************************************************************
 **函数名称: avl_ll_balance
 **功    能: LL型平衡化处理 - 向右旋转(内部接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 左边失去平衡的结点
 **输出参数: NONE
 **返    回: AVL_SUCCESS:成功 AVL_FAILED:失败
 **实现描述: 
 ** 场景1: LL型
 **              A                  B
 **             / \                / \
 **            B   C      ->      BL  A
 **           / \                /   / \
 **          BL BR              X   BR  C
 **         /
 **        X
 **             (1)                (2)
 ** 说明: 结点A是失衡结点,此时当结点B的平衡因子为1时,可判断为LL型。
 **注意事项: 
 **     1. 图(1)中A表示左边失衡的结点 图(2)表示平衡处理的结果
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
int avl_ll_balance(avl_tree_t *tree, avl_node_t *node)
{
    avl_node_t *lchild = node->lchild, *parent = node->parent;

    avl_set_lchild(node, lchild->rchild);
    node->bf = AVL_EH;

    avl_set_rchild(lchild, node);
    lchild->bf = AVL_EH;

    avl_instead_child(tree, parent, node, lchild);

    return AVL_SUCCESS;
}
代码13 LL型平衡化处理(内部接口)
/******************************************************************************
 **函数名称: avl_lr_balance
 **功    能: LR型平衡化处理 - 先左旋转 再向右旋转(内部接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 左边失去平衡的结点
 **输出参数: NONE
 **返    回: AVL_SUCCESS:成功 AVL_FAILED:失败
 **实现描述: 
 ** 场景1: LL型
 **              A                  B
 **             / \                / \
 **            B   C      ->      BL  A
 **           / \                /   / \
 **          BL BR              X   BR  C
 **         /
 **        X
 **             (1)                (2)
 ** 说明: 结点A是失衡结点,此时当结点B的平衡因子为1时,可判断为LL型。
 ** 场景2: LR型
 **              A                    C
 **             / \                /     \
 **            B  AR      ->      B       A
 **           / \                / \     / \
 **          BL  C              BL CL   CR AR
 **             / \
 **            CL CR
 **             (1)                (2)
 ** 说明: 结点A是失衡结点,此时当结点B的平衡因子为-1时,可判断为LR型。
 **       虽然此时结点C的平衡因子的值可能为:-1, 0, 1. 
 **       但旋转处理的方式是一致的,只是旋转之后的平衡因子不一致.
 **注意事项: 
 **     1. 图(1)中A表示左边失衡的结点 图(2)表示平衡处理的结果
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
int avl_lr_balance(avl_tree_t *tree, avl_node_t *node)
{
    avl_node_t *lchild = node->lchild,
        *parent = node->parent, *lrchild = NULL;


    lrchild = lchild->rchild;
    switch(lrchild->bf)
    {
        case AVL_LH:
        {
            node->bf = AVL_RH;
            lchild->bf = AVL_EH;
            lrchild->bf = AVL_EH;
            break;
        }
        case AVL_EH:
        {
           node->bf = AVL_EH;
           lchild->bf = AVL_EH;
           lrchild->bf = AVL_EH;
           break;
        }
        case AVL_RH:
        {
            node->bf = AVL_EH;
            lchild->bf = AVL_LH;
            lrchild->bf = AVL_EH;
            break;
        }
    }

    avl_set_rchild(lchild, lrchild->lchild);
    avl_set_lchild(lrchild, lchild);
    avl_set_lchild(node, lrchild->rchild);
    avl_set_rchild(lrchild, node); 

    avl_instead_child(tree, parent, node, lrchild);

    return AVL_SUCCESS;
}
代码14 LR型平衡化处理(内部接口)
/******************************************************************************
 **函数名称: avl_left_balance
 **功    能: 对左边失去平衡的结点进行平衡化处理(内部接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **     node: 左边失去平衡的结点
 **输出参数: NONE
 **返    回: AVL_SUCCESS:成功 AVL_FAILED:失败
 **实现描述: 
 ** 场景1: LL型
 **              A                  B
 **             / \                / \
 **            B   C      ->      BL  A
 **           / \                /   / \
 **          BL BR              X   BR  C
 **         /
 **        X
 **             (1)                (2)
 ** 说明: 结点A是失衡结点,此时当结点B的平衡因子为1时,可判断为LL型。
 ** 场景2: LR型
 **              A                    C
 **             / \                /     \
 **            B  AR      ->      B       A
 **           / \                / \     / \
 **          BL  C              BL CL   CR AR
 **             / \
 **            CL CR
 **             (1)                (2)
 ** 说明: 结点A是失衡结点,此时当结点B的平衡因子为-1时,可判断为LR型。
 **       虽然此时结点C的平衡因子的值可能为:-1, 0, 1. 
 **       但旋转处理的方式是一致的,只是旋转之后的平衡因子不一致.
 **注意事项: 
 **     1. 图(1)中A表示左边失衡的结点 图(2)表示平衡处理的结果
 **作    者: # Qifeng.zou # 2013.12.13 #
 ******************************************************************************/
int avl_left_balance(avl_tree_t *tree, avl_node_t *node)
{
    avl_node_t *lchild = node->lchild;

    switch(lchild->bf)
    {
        case AVL_LH:    /* 场景1: LL型 */
        {
            return avl_ll_balance(tree, node);
        }
        case AVL_RH:    /* 场景2: LR型 */
        {
            return avl_lr_balance(tree, node);
        }
    }

    return AVL_FAILED;
}
代码15 LL型和LR型平衡处理(内部接口)

3.4 查找结点

  1. /******************************************************************************
  2. **函数名称: avl_search
  3. **功能:查找指定的结点
  4. **输入参数:
  5. **tree:平衡二叉树
  6. **key:需查找的关键字
  7. **输出参数:NONE
  8. **返回: 结点地址
  9. **实现描述:
  10. **注意事项:
  11. **作者:#Qifeng.zou#2013.12.12#
  12. ******************************************************************************/
  13. avl_node_t*avl_search(avl_tree_t*tree,intkey)
  14. {
  15. avl_node_t*node=tree->root;
  16. while(NULL!=node)
  17. {
  18. if(node->key==key)
  19. {
  20. returnnode;
  21. }
  22. elseif(node->key<key)
  23. {
  24. node=node->lc;
  25. }
  26. else
  27. {
  28. node=node->rc;
  29. }
  30. }
  31. returnNULL;/*Didn'tfind*/
  32. }
代码16 查找结点

3.5 销毁对象

销毁二叉树的所有结点往往有2种处理方式:栈处理和递归方式。递归方式简单,但是效率较低;而栈处理的方式比较复杂,在此只是给出递归方式实现。[之前XML处理时的测试,栈销毁比递归销毁的效率高出20%左右,随着深度的增加,其栈的效率还会更高]
/******************************************************************************
 **函数名称: avl_destory
 **功    能: 销毁平衡二叉树(对外接口)
 **输入参数: 
 **     tree: 平衡二叉树
 **输出参数: NONE
 **返    回: VOID
 **实现描述: 
 **注意事项: 
 **作    者: # Qifeng.zou # 2013.12.15 #
 ******************************************************************************/
int avl_destory(avl_tree_t **tree)
{
    if(NULL != tree->root)
    {
        _avl_destory(tree->root);
        tree->root = NULL;
    }
    free(*tree), *tree=NULL;
    return 0;
}
代码17 销毁平衡二叉树
/******************************************************************************
 **函数名称: _avl_destory
 **功    能: 销毁AVL树(内部接口)
 **输入参数: 
 **     node: 需要被销毁的结点
 **输出参数: NONE
 **返    回: VOID
 **实现描述: 
 **注意事项: 
 **作    者: # Qifeng.zou # 2013.12.15 #
 ******************************************************************************/
void _avl_destory(avl_node_t *node)
{
    if(NULL != node->lchild)
    {
        _val_destory(node->lchild);
    }

    if(NULL != node->rchild)
    {
        _val_destory(node->rchild);
    }

    free(node);
}
代码18 销毁结点

3.6 调试程序

以下主函数用来调试和测试以上实现的接口:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <memory.h>


#define INPUT_MAX_LEN (256)
int main(void)
{
    int ret = 0;
    avl_tree_t *tree = NULL;
    avl_node_t *node = NULL;
    char input[INPUT_MAX_LEN] = {0};

    ret = avl_creat(&tree);
    if(ret < 0)
    {
        avl_destory(&tree);
        return -1;
    }

    while(1)
    {
        memset(input, 0, sizeof(input));

        scanf(" %s", input);
        if(!strcasecmp(input, "quit")
            || !strcasecmp(input, "exit")
            || !strcasecmp(input, "q"))
        {
            fprintf(stderr, "Quit!\n");
            break;
        }

        node = val_search(&tree, atoi(input));
        if(NULL != node)
        {
            fprintf(stderr, "parent:[%p] lchild:[%p] rchild:[%p] key:[%d] bf:[%d]\n",
                node->parent, node->lchild, node->rchild, node->key, node->bf);
        }

        ret = val_insert(&tree, atoi(input));
        if(AVL_FAILED == ret)
        {
            fprintf(stderr, "Insert failed!\n");
            continue;
        }
        else if(AVL_NODE_EXIST == ret)
        {
            fprintf(stderr, "Node exist!\n");
            continue;
        }
        fprintf(stderr, "Insert success!\n");
        avl_print(tree);
    }
    
    avl_destory(&tree);
    return 0;
}

代码19 测试程序

随机输入10万条数据,其打印的平衡二叉树的结构如下图所示:


图12 测试结果

作者:邹祁峰

2013年12月13日 17时

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics