1. 背景

因为二叉排序树在平衡的情况下查询效率最佳,AVL树让二叉排序树节点变动后维持平衡(左子树高度-右子树高度 差的绝对值<2)

2. 算法原理

根据节点的平衡因子及插入结果,实际修正二叉树,把不平衡消灭最初时刻

2.1 关于旋转

左旋:子树以右孩子为轴心,整体左旋转,旋转后的状态:原根的右孩子成为新根,原根成为新根的左孩子,新根的原左孩子成为其新左孩子的右孩子(中序遍历顺序未变)

右旋:子树以左孩子为轴心,整体右旋转,旋转后的状态:原根的左孩子成为新根,原根成为新根的右孩子,新根的原右孩子成为其新右孩子的左孩子(中序遍历顺序未变)

2.2 出现不平衡时,调整的原则是

根节点和它孩子必须符号相同(即都是左高或右高,根节点和它的左或右孩子的bf要么都是正数,要么都是负数)。符号一致直接旋转,不一致则需两次操作(即双旋)

(注:出现双旋转时,左孩子或右孩子所在子树需要先旋转,并不会遵守符号相同原则,这一步可以称作符号适配)

2.3 造成不平衡的情况分类及调整方案(4类)

LL(左子树高,左孩子的左子树高)

调整方案:直接右旋转 + bf修正

LR(左子树高,左孩子的右子树高)

调整方案:右孩子子树左旋 => 右旋转 + bf修正

RR(右子树高,右孩子的右子树高)

调整方案:直接左旋转 + bf修正

RL(右子树高,右孩子的左子树高)

调整方案:左孩子子树右旋转 => 左旋转 + bf修正

2.2 其它

==下面只整理了插入操作相关原理==

二叉树中的节点有一个平衡因子(bf,值为常量-1,0,1)分别标识本节点为根的子树当前是右高,等高,左高

插入操作附带更新tag( taller)来判断某节点是否长高

插入函数的递归调用回溯时,会根据所在节点的bf值决定是否调整二叉树(旋转)及更新bf值

(注:一些细节见代码注释)

3. 代码实现

(纸张不够用,最后几张图有的多步合作一步了)

#include #include #include // 平衡因子(bf)的值 #define LH 1 #define EH 0 #define RH -1 typedef struct BiTNode { int data; int bf; struct BiTNode *lchild, *rchild; }BiTNode, *BiTree; void L_Rotate(BiTree *); void R_Rotate(BiTree *); bool InsertAVL(BiTree *, int, bool *); void LeftBalance(BiTree *); void RightBalance(BiTree *); void traverse_mid(BiTree); // 左旋转 void L_Rotate(BiTree *P) { BiTree R; R = (*P)->rchild; (*P)->rchild = R->lchild; R->lchild = *P; *P = R; } // 右旋转 void R_Rotate(BiTree *P) { BiTree L; L = (*P)->lchild; (*P)->lchild = L->rchild; L->rchild = *P; *P = L; } // 左调整 void LeftBalance(BiTree *P) { // 执行到此函数说明本子树的bf已经变为2(并没有显示赋值2,且左孩子树高 // 左孩子不可能为EH,只可能是LH或RH,因为如果是EH,则上一次EH时就已经是不平衡的了 BiTree L, Lr; L = (*P)->lchild; switch (L->bf) { // 匹配手绘图中的LL,右旋处理 case LH: (*P)->bf = L->bf = EH; R_Rotate(P); break; // 匹配手绘图中的LR,双旋处理 case RH: Lr = L->rchild; // 根据Lr的bf修改平衡因子(下面这些bf修改建议亲自手绘下面3种情况来理解, 不需要硬记) // 先修改bf,不影响旋转 switch (Lr->bf) { // 匹配LRB case LH: (*P)->bf = RH; L->bf = EH; break; // 匹配LRA case EH: (*P)->bf = L->bf = EH; break; // 匹配LRC case RH: (*P)->bf = EH; L->bf = LH; break; } Lr->bf = EH; L_Rotate(&(*P)->lchild); R_Rotate(P); } } // 右调整 void RightBalance(BiTree *P) { BiTree R, Rl; R = (*P)->rchild; switch (R->bf) { case RH: (*P)->bf = R->bf = EH; L_Rotate(P); break; case LH: Rl = R->lchild; switch (Rl->bf) { // 匹配RLB case LH: (*P)->bf = EH; R->bf = RH; break; // 匹配RLA case EH: (*P)->bf = R->bf = EH; break; // 匹配RLC case RH: (*P)->bf = LH; R->bf = EH; break; } Rl->bf = EH; R_Rotate(&(*P)->rchild); L_Rotate(P); } } // 插入函数 bool InsertAVL(BiTree *P, int e, bool *taller) { if (!*P) { printf("insert %d\n", e); *P = (BiTree)malloc(sizeof(BiTNode)); (*P)->bf = EH; (*P)->data = e; (*P)->lchild = (*P)->rchild = NULL; *taller = true; } else { if (e == (*P)->data) { *taller = false; return false; } if (e < (*P)->data) { // 插入失败肯定是上面这种找到了匹配的节点 if (! InsertAVL(&(*P)->lchild, e, taller)) { return false; } if (*taller) { // 大画数据结构中的这个表达式有一处刊误 switch ((*P)->bf) { // 左子树插入成功 case LH: printf("At %d bf now %d after insert %d LeftBalance\n", (*P)->data, (*P)->bf, e); LeftBalance(P); // 原来左高,现左长高,则不平衡,调整 *taller = false; // 未长高(不平衡已经消除) break; case EH: (*P)->bf = LH; // 原来平衡,现左长高,则左高 *taller = true; // 长高 break; case RH: (*P)->bf = EH; // 原来右高,现左长高,则平衡 *taller = false; // 未长高 break; } } } else { if (! InsertAVL(&(*P)->rchild, e, taller)) { return false; } if (*taller) { // 右子树插入成功 switch ((*P)->bf) { case LH: (*P)->bf = EH; // 原来左高,现右长高,则平衡 *taller = false; // 未长高 break; case EH: (*P)->bf = RH; // 原来平衡,现右长高,则右高 *taller = true; // 长高 break; case RH: printf("At %d bf now %d after insert %d RightBalance\n", (*P)->data, (*P)->bf, e); RightBalance(P); // 原来右高,现右长高,则调整 *taller = false; // 未长高(不平衡已经消除) break; } } } } return true; } void traverse_mid(BiTree T) { if (!T) return; traverse_mid(T->lchild); printf("%d[%d] ", T->data, T->bf); traverse_mid(T->rchild); } int main(void) { // 标识树是否长高 bool taller; int i; int a[10] = {3, 2, 1, 4, 5, 6, 7, 10, 9, 8}; BiTree T = NULL; for (i=0; i<10; i++) { InsertAVL(&T, a[i], &taller); traverse_mid(T); putchar('\n'); } printf("finally正序遍历:\n"); traverse_mid(T); putchar('\n'); return 0; }

output [root@8be225462e66 c]# gcc avl.c && ./a.out insert 3 3[0] insert 2 2[0] 3[1] insert 1 At 3 bf now 1 after insert 1 LeftBalance 1[0] 2[0] 3[0] insert 4 1[0] 2[-1] 3[-1] 4[0] insert 5 At 3 bf now -1 after insert 5 RightBalance 1[0] 2[-1] 3[0] 4[0] 5[0] insert 6 At 2 bf now -1 after insert 6 RightBalance 1[0] 2[0] 3[0] 4[0] 5[-1] 6[0] insert 7 At 5 bf now -1 after insert 7 RightBalance 1[0] 2[0] 3[0] 4[0] 5[0] 6[0] 7[0] insert 10 1[0] 2[0] 3[0] 4[-1] 5[0] 6[-1] 7[-1] 10[0] insert 9 At 7 bf now -1 after insert 9 RightBalance 1[0] 2[0] 3[0] 4[-1] 5[0] 6[-1] 7[0] 9[0] 10[0] insert 8 At 6 bf now -1 after insert 8 RightBalance 1[0] 2[0] 3[0] 4[-1] 5[0] 6[1] 7[0] 8[0] 9[0] 10[0] finally正序遍历: 1[0] 2[0] 3[0] 4[-1] 5[0] 6[1] 7[0] 8[0] 9[0] 10[0] [root@8be225462e66 c]#

平衡二叉树的构造c语言,平衡二叉树(C语言,又称AVL树,实现LeftBalance,RightBalance)...相关推荐

  1. 一种基于平衡二叉树(AVL树)插入、查找和删除的简易图书管理系统

    目录 1. 需求分析 2. 项目核心设计 2.1 结点插入 2.2 结点删除 3 测试结果 4 总结分析 4.1 调试过程中的问题是如何解决的,以及对设计与实现的回顾讨论和分析 4.2 算法的时间和空 ...

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

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

  3. c语言求平衡因子,平衡二叉树(AVL树)的基本操作

    0x00.平衡二叉树的定义 平衡二叉树(AVL树)是一种特殊的二叉搜索树,只是在二叉搜索树上增加了对"平衡"的需求. 假如一棵二叉搜索树,按照"1,2,3,4,5&quo ...

  4. 平衡查找树C语言程序,C语言数据结构之平衡二叉树(AVL树)实现方法示例

    本文实例讲述了C语言数据结构之平衡二叉树(AVL树)实现方法.分享给大家供大家参考,具体如下: AVL树是每个结点的左子树和右子树的高度最多差1的二叉查找树. 要维持这个树,必须在插入和删除的时候都检 ...

  5. 平衡二叉树及其操作实现_平衡二叉树(AVL树)及C语言实现

    上一节介绍如何使用二叉排序树实现动态查找表,本节介绍另外一种实现方式--平衡二叉树.平衡二叉树,又称为 AVL 树.实际上就是遵循以下两个特点的二叉树: 每棵子树中的左子树和右子树的深度差不能超过 1 ...

  6. 【大话数据结构C语言】57 平衡二叉树(AVL树)

    欢迎关注我的公众号是[CodeAllen],关注回复[1024]获取精品学习资源 程序员技术交流①群:736386324 ,程序员技术交流②群:371394777 平衡二叉排序树 平衡二叉树是一种二叉 ...

  7. (C语言) AVL树 - 自平衡二叉树:插入、删除

    数组a[9] = {4,2,6,1,3,5,7,16,15}; 说明:1.层序遍历AVL树,括号内为每个节点的高度值 2.第二行为删除节点"5"之后的AVL树 Reference: ...

  8. 如何构造平衡二叉树(AVL树)(LL、LR、RL、RR)

    定义:平衡二叉树是一棵二叉排序树,或者为空,或者满足以下条件: 1)左右子树高度差的绝对值不大于1: 2)左右子树都是平衡二叉树. 平衡因子:左子树的高度减去右子树的高度,显然,在平衡二叉树中,每个结 ...

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

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

最新文章

  1. 正则表达式--检查颜色值
  2. Microsoft Academic Search vs Google Scholar
  3. Eclipse详细设置护眼背景色和字体颜色并导出
  4. zoj 3812 状压dp
  5. 平均 3000-20000 块不等,有空接外包私活的入群!
  6. 【Detectron2】使用 Detectron2 训练基于 coco 数据集的目标检测网络
  7. Windows11安全中心打不开怎么办 Win11打不开安全中心解决方法
  8. PMC联手云合作伙伴Canonical加入其Ubuntu OpenStack互通性实验室
  9. freebsd mysql5.7_FreeBSD 环境下Mysql问题解决方法集锦
  10. paip.提升效率----更改数组LIST对象值for与FOREACH
  11. 用Excel表格神速写代码
  12. KEIL下载程序失败系列问题
  13. 国务院正式发布《新一代人工智能发展规划》
  14. 中国省份名称的映射字典
  15. 问卷调查报告html,问卷调查报告格式
  16. C# CS客户端不显示垂直滚动条
  17. Debian6.02 终端中文设置--FBTerm + ucimf
  18. JSHOP2详细使用教程 -- 原创
  19. 将谷歌网盘的文件搬运到百度网盘
  20. 如何通过电脑cmd查看android设备日志

热门文章

  1. 笔记整理:数据处理方式Data Processing
  2. [MATLAB]非线性回归--自配函数(nlinfit)
  3. 7-15 单继承中的构造函数与析构函数 (10 分)
  4. 水果店的location
  5. Antlr g4 入门+深入
  6. VuePress 搭建开发文档
  7. 宝塔安装swoole
  8. 手动生成token_微信小程序登录换取token的教程
  9. 2022来了,用 Python 制作一场环保的烟花秀
  10. Python数据可视化 Pyecharts 制作 ThemeRiver 主题河流图