平衡二叉树是一种二叉排序树,其中每一个节点的左子树和右子树的高度至多等于1,平衡二叉树又称为AVL树。

将二叉树节点的左子树深度减去右子树深度的值称为平衡因子BF,平衡二叉树上所有节点的平衡因子只可能是-1,0或者1。

距离插入点最近的,且平衡因子的绝对值大于1的结点为根的子树,我们称为最小不平衡子树。

平衡二叉树实现原理

先来看一个例子:

对于数组a[10]={3,2,1,4,5,6,7,10,9,8}构建平衡二叉树。

按照二叉排序树的方式插入新的元素,当插入1的时候,使得当前二叉树失去平衡:

当插入5的时候,使得平衡二叉树再次失去平衡:

插入6的时候,同样产生不平衡:

注意:上面的这些不平衡都有一个共同的特点,那就是最小不平衡子树的根的BF同它的孩子(左孩子或者右孩子)的BF是同号的。所以这是仅需要一次旋转就可以了。

当插入到数字9的时候,同样的发生了不平衡:

从上面的图可以看到一次的旋转是不能做到再次的平衡的。所以要两次旋转。

在插入8的时候,同样的发生了不平衡,同样的需要两次调整:

所以总结上面的过程:

当最小不平衡子树根节点的平衡因子BF是大于1的时候,就右旋,小于-1时就左旋。

插入节点后,最小不平衡子树的BF与它的子树的BF符号相反时,就需要对子树节点先进行一次旋转,以使得符号相同后,在反向旋转一次才能够完成平衡操作。

平衡二叉树算法实现

加入了平衡因子,所以在每一个结点中增加一个数据域,这个数据域表示以这个结点为根的二叉树的平衡因子。所以树结点的定义为:

typedef struct BiTNode
{int data;int bf;struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

其实对于二叉平衡树的每一次的调整都可以分成两个步骤:

  • 调整各个结点的BF值
  • 旋转子树结构

先写旋转子树结构代码:

void R_Rotate(BiTree *T)
{BiTree tmp;tmp = (*T)->lchild;(*T)->lchild = tmp->rchild;tmp->rchild = (*T);*T = tmp;
}void L_Rotate(BiTree *T)
{BiTree tmp;tmp = (*T)->rchild;(*T)->rchild = tmp->lchild;tmp->lchild = (*T);*T = tmp;
}

所以当插入一个新的结点,导致树结构不平衡的时候,当树右边超重的时候,要右平衡:(树主体左旋转)

//右平衡,右子树超重
void RightBalance(BiTree *T)
{BiTree tmp, tmpr;tmp = (*T)->rchild;switch (tmp->bf){case -1:(*T)->bf = 0;tmp->bf = 0;L_Rotate(T);break;case 1:tmpr = tmp->lchild;switch (tmpr->bf){case 1:tmp->bf = -1;(*T)->bf = 0;break;case -1:tmp->bf = 0;(*T)->bf = 1;break;case 0:tmp->bf = (*T)->bf = 0;}tmpr->bf = 0;//R_Rotate(&tmp);是错误的,因为不能修改上一级的指针R_Rotate(&(*T)->rchild);L_Rotate(T);}
}

当插入一个结点导致树结构不平衡的时候,左子树超重,要左平衡:(树主体右旋转)

//左平衡,左子树超重
void LeftBlance(BiTree *T)
{BiTree tmp,tmpr;tmp = (*T)->lchild;switch (tmp->bf){case 1:(*T)->bf = 0;tmp->bf = 0;R_Rotate(T);break;case -1:tmpr = tmp->rchild;switch (tmpr->bf){case 1:tmp->bf = 0;(*T)->bf = -1;break;case -1:tmp->bf = 1;(*T)->bf = 0;break;case 0:(*T)->bf = 0;tmp->bf = 0;break;}//switchtmpr->bf = 0;//L_Rotate(&tmp);是错误的,因为不能修改上一级的指针L_Rotate(&(*T)->lchild);R_Rotate(T);}
}

注意:上面两处的双旋转的时候,不能旋转tmp,因为这样不能把父结点的指针修改,所以要旋转父结点指下来得指针。

最后插入操作的主函数:

bool InsertAVL(BiTree *T, int key, bool *taller)
{if (*T ==NULL){*T = (BiTree)malloc(sizeof(BiTNode));(*T)->data = key;(*T)->lchild = (*T)->rchild = NULL;(*T)->bf = 0;*taller = true;return true;}if((*T)->data == key){*taller = false;return false;}else if((*T)->data > key){if(!InsertAVL(&(*T)->lchild, key, taller))return false;if(*taller){switch ((*T)->bf){case 1:LeftBlance(T);*taller = false;break;case 0:(*T)->bf = 1;*taller = true;break;case -1:(*T)->bf = 0;*taller = false;break;}//switch}//if}//else ifelse   //(*T)->data < key{if (!InsertAVL(&(*T)->rchild, key, taller))return false;if(*taller){switch ((*T)->bf){case 1:(*T)->bf = 0;*taller = false;break;case 0:(*T)->bf = -1;*taller = true;break;case -1:RightBalance(T);*taller = false;}//switch}//if}//elsereturn true;
}

  

  

转载于:https://www.cnblogs.com/stemon/p/4839019.html

[树结构]平衡二叉树AVL相关推荐

  1. Python数据结构11:树的实现,树的应用,前中后序遍历,二叉查找树BST,平衡二叉树AVL树,哈夫曼树和哈夫曼编码

    1.概念 树一种基本的"非线性"数据结构. 相关术语: 节点Node:组成树的基本部分.每个节点具有名称,或"键值",节点还可以保存额外数据项,数据项根据不同的 ...

  2. java 二叉树特点_java学习笔记-二叉树、平衡二叉树(AVL)、红黑二叉树(十)

    各种树 标签:数据结构范畴 二叉树的定义: 二叉树是树形结构的一个重要类型. 许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为 ...

  3. [转]C#与数据结构--树论--平衡二叉树(AVL Tree)

    C#与数据结构--树论--平衡二叉树(AVL Tree) http://www.cnblogs.com/abatei/archive/2008/11/17/1335031.html 介绍 我们知道在二 ...

  4. 平衡二叉树AVL详解

    一.平衡二叉树的定义 平衡二叉树(Balanced Binary Tree)又被称为AVL树,它且具有以下性质: (1)它是一棵空树或它的左右两个子树的高度差的绝对值不超过1: (2)并且左右两个子树 ...

  5. 平衡二叉树平衡因子怎么计算_数据结构PHP 平衡二叉树(AVL)的平衡原理

    这篇文章主要介绍一下 平衡二叉树(AVL),对于 二分搜索树 来说,如果树上的 元素 是顺序 添加的,会导致数据退化成一个 链表,这样就会造成很严重的性能问题,此时就需要在 二分搜索树 的基础上,保证 ...

  6. [ 数据结构 ] 平衡二叉树(AVL)--------左旋、右旋、双旋

    0 引出 数列{1,2,3,4,5,6},要求创建一颗二叉排序树(BST), 并分析问题所在 回顾:二叉搜索树 左子树全部为空,从形式上看,更像一个单链表. 插入速度没有影响 查询速度明显降低(因为需 ...

  7. Java数据结构——平衡二叉树(AVL树)

    AVL树的引入 搜索二叉树有着极高的搜索效率,但是搜索二叉树会出现以下极端情况: 这样的二叉树搜索效率甚至比链表还低.在搜索二叉树基础上出现的平衡二叉树(AVL树)就解决了这样的问题.当平衡二叉树(A ...

  8. 二叉树(BT)、二叉查找树(BST)、平衡二叉树(AVL)、B-Tree、B+Tree、红黑树(BRT)

    目录 树的概念 树的分类 二叉树 二叉查找树 平衡二叉树(AVL) B-Tree(平衡多路查找树) B树的关键特征 B+Tree B+树关键特征 红黑树(BRT) 左旋 右旋 时间复杂度 树形结构是一 ...

  9. 数据结构——平衡二叉树(AVL树)之插入

    文章目录 前言 一.定义 二.基本操作 1.查找, 2.插入(如何调整) 如何调整 代码实现插入 前言 首先我们来思考一下一个普通二叉树保存数据,如果想查找一个数据,由于普通二叉树保存数据是随机的,要 ...

最新文章

  1. php mysql 时间戳查询_mysql中时间查询函数(包括时间戳)
  2. JVM调优总结 -Xms -Xmx -Xmn -Xss等
  3. 远程计算机串口控制软件,智能控制的设备上使用远程开关需要用到RS485串口继电器、网关、电脑平台...
  4. linux生成数字命令,Linux下随机生成密码的命令
  5. 工业交换机和工业路由器的区别
  6. 索引会自动更新吗_mysql的B+树中数据存放结构和索引常见问题你会吗?
  7. mysql group by能用到索引吗_`MySQL GROUP BY使用索引时速度较慢
  8. gb和gib的区别_不同软硬件环境下NVMe SSD性能简测和一些SSD测试建议
  9. 电路分析之正弦稳态电路的仿真与研究
  10. 20162327WJH实验四——图的实现与应用
  11. 2016全球排名前50的博客网站性能
  12. 2016——大数据版图
  13. day13课后总结App
  14. jupyter notebook 常用魔法函数 Magic Function%time %timeit %who %pip %cd
  15. border-radius使用详解
  16. 微信小程序 柱状图的使用
  17. goframe与gin对比(一) 综述
  18. 【2022】年度总结
  19. 对于建立图书馆管理系统的项目模拟经验
  20. 3D超声图像徒手freehand三维重建

热门文章

  1. 终于,我读懂了所有Java集合——queue篇
  2. 算法总结-1算法入门
  3. 《Head First设计模式》第五章笔记-单件模式
  4. UNIX(多线程):19---Future 类型详解
  5. 我们边吃曲奇边聊——Cookie与Session那些事
  6. 通过解析URL实现通过Wifi的用户查找
  7. STL源码剖析 map
  8. Android之android.os.Build
  9. 研发团队平稳度过“从小到大”并非易事
  10. C语言extern关键词—最会带帽子的关键字