前一篇博客学习了高效动态表查找的二叉排序树,虽然在二叉排序树上实现的插入,删除和查找等基本操作的平均时间为O(log2(n)),但随着插入和删除操作导致树形的改变,成为单枝树,只能从根开始一层一个查找,实质变为顺序查找,此时就是最坏的情况,基本运算的时间会增至O(n);为了避免这种情况,我们可以使用平衡二叉树,使之即保存BST性质又保证树的高度至多左右子树相差一。平衡二叉树有较多种,我们主要介绍较为著名的AVL树。
平衡二叉树(AVL)
1.概念介绍
平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
我们通过平衡因子来具体实现上述的平衡二叉树的定义,平衡因子的定义为:平衡二叉树中每一个结点有一个平衡因子域,每个结点的平衡因子是该结点左子树的高度减去右子树的高度。若一棵二叉树中所有结点的平衡因子的绝对值小于或等于1,则该树成为平衡二叉树。
例如:
每个结点旁边标记的就是该结点的平衡因子,具体计算如下:
我们看图a,左子树高度减去右子树高度,得
5的结点平衡因子就是 3 - 2 = 1;
2的结点平衡因子就是 1 - 2 = -1;
4的结点平衡因子就是 1 - 0 = 1;
6的结点平衡因子就是 0 - 1 = -1;
2.结点插入
首先我们定义树结点的结构为:
//树结点结构 struct node { int data;//数据 int bf;//平衡因子 node*lchild,*rchild; node() { lchild=rchild=NULL; } };
在平衡二叉树中插入结点与二叉查找树最大的不同在于要随时保证插入后整棵二叉树是平衡的。若插入的新结点破坏了平衡性首先要从根节点到该新结点的路径逆向找到第一个失去平衡的结点。在这里我们要介绍失去平衡的最小子树的概念。
失去平衡的最小子树是指以离插入结点最近,且平衡因子绝对值大于1的结点作为根的子树。假设用A表示失去平衡的最小子树的根结点,则调整该子树的操作可归纳为下列四种情况。(1)LL型调整
由于在A的左孩子B的左子树上插入结点F,使A的平衡因子由1增至2而失去平衡。故需进行一次顺时针旋转操作。 即将A的左孩子B向右上旋转代替A作为根结点,A向右下旋转成为B的右子树的根结点。而原来B的右子树则变成A的左子树。
如图所示:
代码实现:
void L_rotata(node * &p){//左旋, node * rc=p->rchild; p->rchild=rc->lchild; rc->lchild=p; p=rc; }
(2)RR型调整
由于在A的右孩子C 的右子树上插入结点F,使A的平衡因子由-1减至-2而失去平衡。故需进行一次逆时针旋转操作。即将A的右孩子C向左上旋转代替A作为根结点,A向左下旋转成为C的左子树的根结点。而原来C的左子树则变成A的右子树。
如图所示:
实现代码:
void R_rotate(node * &p){//右旋, node * lc=p->lchild; p->lchild=lc->rchild; lc->rchild=p; p=lc; }
(3)LR型调整
由于在A的左孩子B的右子数上插入结点F,使A的平衡因子由1增至2而失去平衡。故需进行两次旋转操作(先逆时针,后顺时针)。即先将A结点的左孩子B的右子树的根结点D向左上旋转提升到B结点的位置,然后再把该D结点向右上旋转提升到A结点的位置。即先使之成为LL型,再按LL型处理
如图所示:
先将圆圈部分先调整为平衡树,然后将其以根结点接到A的左子树上,此时成为LL型,再按LL型处理成平衡型。
实现代码:
void Leftbalance(node * &T){//左子树的平衡处理 node * lc=T->lchild; switch(lc->bf){ //LL的情况 case LH: T->bf=lc->bf=EH; R_rotate(T); break; case RH://LR的情况,同时针对rd上的不同情况,进行对T,lc的平衡因子的设置 node * rd=lc->rchild; switch(rd->bf){ case LH:T->bf=RH; lc->bf=EH;break; case EH:T->bf=lc->bf=EH;break; case RH:T->bf=EH;lc->bf=LH;break; } rd->bf=EH; L_rotata(T->lchild); R_rotate(T); } }
(4)RL型调整
由于在A的右孩子C的左子树上插入结点F,使A的平衡因子由-1减至-2而失去平衡。故需进行两次旋转操作(先顺时针,后逆时针),即先将A结点的右孩子C的左子树的根结点D向右上旋转提升到C结点的位置,然后再把该D结点向左上旋转提升到A结点的位置。即先使之成为RR型,再按RR型处理。
如图所示:
先将圆圈部分先调整为平衡树,然后将其以根结点接到A的左子树上,此时成为RR型,再按RR型处理成平衡型。
实现代码:
void Rightbalance(node * &T)//右子树的平衡处理,与左子树的平衡处理类似 { node * rc=T->rchild; switch (rc->bf) { case RH: T->bf=rc->bf=EH; L_rotata(T);break; case LH: node * ld=rc->lchild; switch(ld->bf){ case LH: T->bf=EH; rc->bf=RH;break; case EH: T->bf=rc->bf=EH;break; case RH: T->bf=LH; rc->bf=EH;break; } ld->bf=EH; R_rotate(T->rchild); L_rotata(T); } }
含有n个结点的平衡二叉树的平均查找长度为O(log2(n));
附上源码地址:https://github.com/longpo/algorithm/tree/master/AVL
相关推荐
"算法大全-面试题-链表-栈-二叉树-数据结构"这个压缩包文件提供了丰富的知识资源,旨在帮助学习者深入理解和应用这些核心概念。 链表是一种线性数据结构,与数组不同,它的元素在内存中不是连续存储的。链表由一...
4. 更新树结构:当矩形插入后,可能需要调整周围矩形的位置或分割现有矩形以适应新的空间划分,这会导致二叉树结构的更新。 5. 重复步骤3和4,直到所有矩形都装入。 6. 输出结果:最后,遍历二叉树,按照层次顺序...
这个压缩包文件"算法-树形结构- 树与二叉树- 树的数据生成器.rar"显然聚焦于介绍如何生成和操作树和二叉树的数据。尽管没有具体的标签,我们可以从标题和描述中推测其内容可能涵盖了以下几个关键知识点: 1. **树的...
这个压缩包文件“算法-理论基础- 二叉树- 树、森林、二叉树的转换(包含源程序).rar”包含了关于树、森林以及它们与二叉树之间转换的理论知识和实际编程示例。让我们深入探讨这些概念。 首先,树是一种非线性的...
通过阅读和分析这些代码,你可以更好地掌握二叉树的动态插入、删除和查找算法,这对于提升编程能力和解决实际问题至关重要。 二叉树在计算机科学的许多领域都有广泛应用,如编译器设计(语法分析树)、数据库索引...
平衡二叉树是一种特殊的二叉树数据结构,它在保持二叉查找树特性的同时,通过特定的结构调整,确保了树的高度平衡。这种平衡使得在树中的查找、插入和删除操作的时间复杂度达到最优,通常为O(log n),其中n是树中...
树的重心在算法设计中扮演着关键角色,特别是在平衡树结构中。例如,在构建AVL树时,为了保持树的平衡,我们需要在插入或删除节点后重新计算树的重心,并可能执行相应的旋转操作。此外,重心还与树的搜索、插入和...
源代码文件“算法-理论基础- 二叉树- 三叉链表(包含源程序).pdf”很可能包含了具体的实现细节和示例,涵盖了如何创建、遍历以及在二叉树和三叉链表上执行操作的方法。通过阅读这些源码,你可以了解如何用编程语言...
2. **树的类型**:包括完全树、满树、平衡树、不平衡树、二叉树等。其中,二叉树是最特殊的树形结构,每个节点最多有两个子节点。 3. **二叉树**:二叉树分为不同的类型,如满二叉树、完全二叉树、平衡二叉树(如...
平衡二叉树是一种特殊的二叉树结构,其中每个节点的两个子树的高度差不超过1,以确保树的平衡,从而优化查找、插入和删除等操作的时间复杂度。AVL树是最早被提出的自平衡二叉搜索树,由G. M. Adelson-Velsky和E. M. ...
平衡二叉树,如AVL树或红黑树,是一种特殊的二叉搜索树,它的特点是左右子树的高度差不超过1,这确保了树的平衡性,从而保证了查找、插入和删除操作的时间复杂度为O(log n)。在实验中,学生将学习如何实现这些基本...
在C/C++代码资源中,你可能找到了实现这些平衡二叉树算法的示例代码,包括节点结构定义、插入、删除和查找操作的函数实现,以及相应的平衡调整逻辑。通过学习和理解这些代码,你可以深入掌握平衡二叉树的工作原理,...
虽然提供的部分内容涉及静态查找表及哈希表,但为了贴合标题“数据结构与算法-二叉树的查找”,我们将集中讨论二叉树的基本概念及其查找算法。 ### 二叉树的基本概念 二叉树是一种树形数据结构,其中每个节点最多...
平衡二叉树是一种特殊的二叉树结构,它的主要特性是左右子树的高度差不超过1,保证了树的形态均匀,从而在查找、插入和删除等操作上的效率接近于最佳的二叉查找树。这种特性使得平衡二叉树在数据结构和算法中占有...
此外,还有平衡二叉树(如AVL树和红黑树)用于优化查找效率。 这个压缩包中的C++实现代码可以帮助学习者深入理解这些算法和数据结构的实际应用。通过阅读和运行这些代码,不仅可以巩固理论知识,还能提升编程能力。...
查找算法是计算机科学领域中极为重要的组成部分之一,主要用于在数据集合中查找特定元素。根据数据组织的不同以及效率需求的差异,不同的查找算法被设计出来以适应各种场景。本文将详细介绍几种常见的查找算法:顺序...
这里我们将深入探讨两种常见的查找算法:二叉树查找和折半查找。 首先,我们来了解一下**折半查找**(也称为二分查找)。这种算法适用于有序的数据集合,如数组。其基本思想是每次将查找区间缩小一半,直到找到目标...
这个实验不仅加深了对二叉查找树的理解,还锻炼了实际编程实现查找算法的能力,是学习数据结构与算法过程中非常有价值的一环。通过实验,学生能够更好地掌握二叉查找树的插入操作、遍历方法以及验证树的正确性,为...
- **平衡算法**:AVL树和红黑树等自平衡二叉搜索树,保证了搜索效率。 5. **C#实现细节** - **递归实现**:遍历和搜索等操作通常用递归实现,避免了栈空间问题,代码简洁易懂。 - **迭代实现**:使用栈或队列...
总结而言,二叉树是基础且重要的数据结构,平衡二叉树如AVL树和红黑树则通过保持树的平衡优化了操作效率。平均查找长度是衡量查找性能的关键指标,而二叉树的删除操作则需要根据节点的子节点情况灵活处理。源代码...