入门二叉平衡树的世界

1. 二叉平衡树的概念

    二叉平衡树又称AVL树,它或者是一棵空二叉树,或者是具有下列性质的二叉树:
1) 根的左右子树高度之差的绝对值不超过1;
2) 根的左右子树都是二叉平衡树。
二叉树上节点的平衡因子定义为该节点的左子树的高度减去右子树的高度,故AVL树的所有节点的平衡因子只可能是-1、0、1. 
    二叉平衡树是一种特殊的二叉搜索树,能够控制树的高度,避免产生普通二叉搜索树的退化树形。AVL树是对二叉搜索树的一种改进,二叉搜索树的缺点就是:树的结构是无法预料的,随意性很大,它只与节点的值和插入的顺序有关系,往往得到的是一个不平衡的二叉树。在最坏的情况下,可能得到的是一个单支二叉树,其高度和节点数相同,相当于单链表,对其正常的查找的时间复杂度就不是O(log n),而是O(n),也就丧失了二叉搜索树的一些应有的优点。
    当插入一个新的节点的时候,在普通的二叉树中不同考虑树的平衡因子,只要将大于根节点的值插入到右子树,小于节点的值插入到左子树,递归即可。但是,AVL树在插入节点的时候,如果插入节点之后有一个节点的平衡因子要大于或者小于-2的时候,需要进行调整。
2. 二叉平衡树的4种调整方式
    二叉平衡树中最复杂的就要数4种调整方式了:LL、RR、LR和RL。对二叉平衡树的插入和删除,在每次插入和删除一个节点之后都有可能破坏其平衡性,此时就需要调整。这点和建立最大堆和最小堆是一致的思想。下面我们就详细介绍一下如何实现这4种调整:
    在介绍调整之前,需要理解最小不平衡子树的概念:如果在插入节点前,从根节点到新节点插入位置的路径上的所所有节点的平衡因子bf均为0,那么插入后这棵树仍然是二叉平衡树,而高度加1;如果在这条路径上,某个节点(设由指针s指示)的平衡因子不为0,但自它以下直至新节点的所有节点的平衡因子原先都为0,那么插入后,以节点s为根节点的子树就有可能是最小不平衡子树。我们调整的范围业绩是这棵最小不平衡子树。
1)LL型调整:
LL型就是在A节点的左子树B的左子树C上插入新节点new。调整的步骤为:
step 1:B节点作为新的节点,那么就需要把B的右子树x给A的左子树;
step 2:B节点为左子树,那么右子树即为A,把A给B的右子树;
step 3:A和B的平衡因子设置0,C的平衡因子不变;
2)RR型调整:
RR型就是在A右子树B的右子树C插入一个新节点new,调整的步骤如下:
step 1:B作为新的根节点,先把B的左子树x赋给A的右子树;
step 2:因为B是新的根节点,C为B的右子树,把A赋给B的左子树;
step 3:A和B的平衡因子为0,C的平衡因子不变;
3)LR型调整:
LR型就是在A左子树B的右子树C插入一个新节点,调整的步骤如下:
step 1:C作为新的根节点;
step 2:先把C的右子树CR赋给A的左子树,C的左子树CL赋给B的右子树;
step 3:再把B作为C的左子树,A作为C的右子树,C作为新的根节点;
step 4:如果原先C的平衡因子bf=1,则A的新bf为-1,B的新bf为0;
             如果原先C的平衡因子bf=-1,则A的新bf为0,B的新bf为1;
             如果原先C的平衡因子bf=0,则A的新bf为0,B的新bf为0;
4)RL型调整:
RL型就是在A右子树B的左子树C插入一个新节点,调整的步骤如下:
step 1:C作为新的根节点;
step 2:先把C的右子树CR赋给B的左子树,C的左子树CL赋给A的右子树;
step 3:再把A作为C的左子树,B作为C的右子树,C作为新的根节点;
step 4:如果原先C的平衡因子bf=1,则A的新bf为0,B的新bf为-1;
             如果原先C的平衡因子bf=-1,则A的新bf为1,B的新bf为0;
             如果原先C的平衡因子bf=0,则A的新bf为0,B的新bf为0;

插入节点的代码如下:(网上复制的,自己敲了一遍)
#include <iostream.h>
#include <string.h>
#define NUM 10
typedef int KeyType;
class AVLTree;
class AVLNode
{
public:KeyType key;//任意一结点的左子树深度减去右子树的//深度称为该节点的平衡因子.int bf;      //记录平衡因子AVLNode *lchild;AVLNode *rchild;AVLNode(){lchild = NULL;rchild = NULL;bf = 0;}
};//平衡二叉排序树
class AVLTree
{
public:AVLNode *root;AVLTree(){root = NULL;}AVLNode* LL_Rotate( AVLNode *a );     //LL(顺时针)型调整AVLNode* RR_Rotate( AVLNode *a );     //RR(逆时针)型调整AVLNode* LR_Rotate( AVLNode *a );     //LR(先逆后顺)型调整AVLNode* RL_Rotate( AVLNode *a );     //RL(先顺后逆)型调整void AVLInsert( AVLNode *&pavlt, AVLNode *s );   //插入一个新结点
}; /***  LL(顺时针)型调整*  */
AVLNode* AVLTree::LL_Rotate( AVLNode *a )
{  if( a == NULL ){cout <<  "the pointer is null!" << endl;return NULL;}AVLNode *b;b = a->lchild;       //b指向a的左子树根结点a->lchild = b->rchild;  //b的右子树挂在a的左子树上b->rchild = a;a->bf = b->bf = 0;return b;
}/***  RR(逆时针)型调整*  */
AVLNode* AVLTree::RR_Rotate( AVLNode *a )
{  if( a == NULL ){cout <<  "the pointer is null!" << endl;return NULL;}AVLNode *b;b = a->rchild;a->rchild = b->lchild;b->lchild = a;a->bf = b->bf = 0;return b;
}/***  LR(先逆后顺)型调整*  */
AVLNode* AVLTree::LR_Rotate( AVLNode *a )
{  if( a == NULL ){cout <<  "the pointer is null!" << endl;return NULL;}AVLNode *b, *c;b = a->lchild;c = b->rchild;a->lchild = c->rchild;b->rchild = c->lchild;c->lchild = b;c->rchild = a;//调整平衡因子if( c->bf == 1 ){a->bf = -1;b->bf = 0;}else if( c->bf == -1 ){a->bf = 0;b->bf = 1;}else{b->bf = a->bf = 0;}c->bf = 0;return c;
}/***  RL(先顺后逆)型调整*  */
AVLNode* AVLTree::RL_Rotate( AVLNode *a )
{  if( a == NULL ){cout <<  "the pointer is null!" << endl;return NULL;}AVLNode *b, *c;b = a->rchild;c = b->lchild;a->rchild = c->lchild;b->lchild = c->rchild;c->lchild = a;c->rchild = b;//调整平衡因子if( c->bf == 1 ){a->bf = 0;b->bf = -1;}else if( c->bf == -1 ){a->bf = 1;b->bf = 0;}else{a->bf = b->bf = 0;}c->bf = 0;return c;
}/***  将结点s插入pavlt为根结点的平衡二叉排序树中*  */
void AVLTree::AVLInsert( AVLNode *&pavlt, AVLNode *s )
{AVLNode *f, *a, *b, *p, *q;if( pavlt == NULL ){pavlt = s;return;}a = pavlt;f = NULL;p = pavlt;q = NULL;//寻找插入点位置及最小不平衡树的子树while( p != NULL ){if( p->key == s->key )   //AVL中已经存在关键字return;if( p->bf != 0 )         //寻找最小不平衡子树{a = p;f = q;}q = p;if( s->key < p->key )    p = p->lchild;elsep = p->rchild;}if( s->key < q->key )        //将结点*s插入到合适的位置上去q->lchild = s;elseq->rchild = s;p = a;while( p != s )            //插入结点后修改相应的平衡因子{if( s->key < p->key ){p->bf++;p = p->lchild;}else{p->bf--;p = p->rchild;}}if( a->bf > -2 && a->bf < 2 )  //插入结点后没有破坏平衡树return;if( a->bf == 2 ){b = a->lchild;if( b->bf == 1 )           //结点插在*a的左孩子的左子树中p = LL_Rotate( a );    //LL型调整else                       //结点插在*a的左孩子的右子树中p = LR_Rotate( a );    //LR型调整}else{b = a->rchild;if( b->bf == 1 )          //结点插在*a的右孩子的左子树中p = RL_Rotate( a );   //RL型调整else                      //结点插在*a的右孩子的右子树中p = RR_Rotate( a );   //RR型调整}if( f == NULL )               //原*a是AVL树的根pavlt = p;else if( f->lchild == a )     //将新子树链到原结点*a的双亲结点上f->lchild = p;else f->rchild = p;
}/***   在VC6.0下测试成功*   cheneagle:2009.8.6 */
int main( void )
{int a[NUM] = { 34, 18, 13, 73, 16, 52, 58, 67, 82, 76 };int i = 0;AVLTree tree;AVLNode pNode[NUM], *p = NULL;for( i = 0; i < NUM; i++ ){pNode[i].key = a[i];tree.AVLInsert( p, &pNode[i] );}return 0;
}

关于二叉平衡树的删除,我们也是先用二叉搜索树的删除节点方法(较插入复杂),然后再调整。

以后有时间了也写一遍删除的代码。

入门二叉平衡树的世界相关推荐

  1. 入门二叉搜索树的世界

    入门二叉搜索树的世界 1. 二叉搜索树的概念     二叉搜索树,二叉查找树,二叉排序树说的都是一个概念.这篇博文中我们称其为二叉搜索树.二叉搜索树指的是一棵空树,或者具有下列性质的二叉树: 1)弱左 ...

  2. 数据结构源码笔记(C语言):二叉平衡树的相关操作算法

    //二叉平衡树的相关运算 #include<stdio.h> #include<malloc.h> #include<string.h>typedef char I ...

  3. 数据结构与算法——二叉平衡树(AVL树)详解

    文章目录 AVL树概念 不平衡概况 四种平衡旋转方式 RR平衡旋转(左单旋转) LL平衡旋转(右单旋转) RL平衡旋转(先右后左双旋转) LR平衡旋转(先左后右单旋转) java代码实现 总结 AVL ...

  4. AVL树(二叉平衡树)详解与实现

    公众号文章链接 AVL树概念 前面学习二叉查找树和二叉树的各种遍历,但是其查找效率不稳定(斜树),而二叉平衡树的用途更多.查找相比稳定很多.(欢迎关注数据结构专栏) AVL树是带有平衡条件的二叉查找树 ...

  5. 【Python数据结构】——二叉平衡树AVL(查找、构建、删除、插入、打印、遍历)

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2021/7/28 20:57 # @Author : @linlianqin # @S ...

  6. 二叉平衡树平衡方法(RR、LL、RL、LR)

    二叉平衡树的平衡方法 (RR.LL.RL.LR) 1.RR型 右单旋 右右型:插入节点在不平衡因子节点右子树的右边 右单旋:向左旋转 2.LL型 左单旋 左左型:插入节点在不平衡因子节点的左子树的左边 ...

  7. 【数据结构进阶】二叉平衡树

    一. 二叉平衡树 概念 二叉搜索树有称 二叉排序树,它也可以是一个空树. 如果它的左子树不为空,则左子树上所有结点的值都小于根结点的值 如果他的右子树不为空,则右子树上所有结点的值都大于根结点的值 它 ...

  8. C语言实现二叉平衡树

    [前置知识]二叉树和二叉排序树 目录 1.什么是AVL树 2.怎么平衡 前言 对于大量的数据而言,链表的线性访问时间太慢,不宜使用.本章节将会介绍一种简单的数据结构:树(tree),其大部分操作的运行 ...

  9. 二叉平衡树(C++)

    背景: 二叉平衡树,就是根据二叉搜索树进行优化,让其速度更加的快,如果读者没有学过二叉搜索树,可以前往以下链接查看资料: http://t.csdn.cn/Sjjjshttp://t.csdn.cn/ ...

最新文章

  1. eSpeak: Linux 文本转语音工具
  2. python手机版打了代码运行不了-android手机安装python并写代码运行
  3. 一、MySQL数据库基础
  4. CodeForces - 858D Polycarp's phone book(字典树/map)
  5. Windows 2008之Hyper-V安装攻略
  6. Spring Data MongoDB教程
  7. latex 调整表格的行高_latex 表格如何控制行高,行距,行与行之间的距离
  8. IR2104电机驱动
  9. PS更换证件照背景色,并去除人物像边线
  10. F28335课后习题记录
  11. 世界各地 史上最全最详细无线通信频率分配表(内容含概wifi、2.4G、5G,绝对值得收藏)
  12. 如何输出一个国际象棋棋盘
  13. 取消研究生论文发表需求,985大学官宣!
  14. 关于mysql答辩的问题_答辩常见问题总结.doc
  15. phpStrom连接MySQL数据库
  16. 点云ply格式文件详解
  17. 亚马逊测评提升销量有什么好办法,分享6点技巧
  18. busblaster-v3c调试hg255d的脚本代码
  19. UDP与IP的不可靠程度是否相同
  20. 师夷之技以制夷 吾尝终日而思矣,不如须臾之所学也

热门文章

  1. 矽杰微 X8E1101 单片机
  2. 面试高频问题——“淘宝购物车”怎么测试
  3. emlog媒体范美化版v6.3.1
  4. matlab数据统计和分析
  5. visio中公式太小_针织布的价格计算公式你学会了吗?
  6. 百度「文心一言」阿里「通义千问」腾讯的AI将会叫什么呢
  7. 外汇交易经济指标解读
  8. SQL Server 判断时间是一年的第几周、星期几
  9. 字典树 —— 字符串分析算法
  10. poi导出excel文件,并生成原生图表(包括折线图,柱状图,饼状图,面积图)