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

本文介绍了平衡二叉树(AVL树)的概念,重点讲解了在插入节点后如何处理四种不平衡情况:LL型、LR型、RR型和RL型。此外,还提供了创建、插入、查找和销毁AVL树的操作接口,以及C语言实现的查找函数示例。
摘要由CSDN通过智能技术生成
               

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的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值