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

本文介绍了平衡二叉树(AVL树)的概念,包括平衡因子和四种失衡情况(LL型、LR型、RR型、RL型)。详细阐述了在插入新节点后如何进行平衡调整,并提供了C语言实现的avl_search查找节点的函数。此外,文章还提到了平衡二叉树在性能上的优势,以解决二叉排序树在最坏情况下的效率问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.youkuaiyun.com/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

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 结构定义

->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 结点结构
->2 树结构定义
/* 树结构 */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 平衡二叉树结构
->3 错误码:可根据实际情况动态扩展
typedef enum{    AVL_SUCCESS                   /* 成功 */    , AVL_FAILED = ~0x7FFFFFFF    /* 失败 */    , AVL_NODE_EXIST              /* 结点存在 */    , AVL_ERR_STACK               /* 栈异常 */}AVL_RET_e;
代码3 返回值定义
->4 其他定义:
/* 平衡因子 */#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 查找结点

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  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, int key)  
  14. {  
  15.     avl_node_t *node = tree->root;  
  16.   
  17.     while (NULL != node) {  
  18.         if (node->key == key) {  
  19.             return node;  
  20.         }  
  21.         else if (node->key < key) {  
  22.             node = node->lc;  
  23.         }  
  24.         else{  
  25.             node = node->rc;  
  26.         }  
  27.     }  
  28.   
  29.     return NULL; /* Didn't find */  
  30. }  
代码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 测试结果


           

给我老师的人工智能教程打call!http://blog.youkuaiyun.com/jiangjunshow
这里写图片描述
# 欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block var foo = 'bar'; 

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t &ThinSpace; . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

gantt
        dateFormat  YYYY-MM-DD
        title Adding GANTT diagram functionality to mermaid
        section 现有任务
        已完成               :done,    des1, 2014-01-06,2014-01-08
        进行中               :active,  des2, 2014-01-09, 3d
        计划一               :         des3, after des2, 5d
        计划二               :         des4, after des3, 5d
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值