平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树,同时,平衡二叉树必定是二叉排序树。

高度差可以用平衡因子bf来定义,我们用左子树的高度减去右子树的高度来表示bf,即-1<|bf|<1。

引入平衡二叉树是由于二叉排序树,在某些情况会导致树的高度一直的增加,比如一组有序的数据,在查找或创建时递归层级会很深,导致方法栈容易溢出。

平衡二叉树是通过旋转来缓解树高度增加过快的情况。

先介绍下最小不平衡节点的概念:插入一个节点之后,距离这个插入节点最近的不平衡节点就是最小不平衡节点。就是说在递归插入节点后,开始回溯,碰到的第一个不平衡的节点就是最小不平衡节点。

当最小不平衡节点右子树高则需要左旋,左子树高则需要右旋(还有些情况需要先对其左/右子树旋转)。

思考:

1、既然旋转是通过平衡因子|bf|>1来决定怎么旋转的,那么在旋转前这些平衡因子是什么时候赋值的呢?

2、旋转之后,哪些节点需要调整?,平衡因子又改如何调整呢?

下图只列出左子树高的几种情况,T表示最小不平衡节点,L表示其左子树,LR表示L的右子树,

为了形象用EH(0),LH(1),RH(-1)分别表示某一节点 左右子树相等、左子树高、右子树高三种情况。

根据L节点的左右子树高度差来确定直接右旋还是先左旋再右旋,因为L为最小不平衡子树的左子树,故不会出现L.bf=EH的情况。

一、L.bf=LH

右旋:

旋转之后T.bf=L.bf=EH

二、L.bf=RH

先左旋再右旋:

当L的平衡因子为-1时则需要先对L进行右旋,然后再对T进行左旋。根据LR的情况再分为下面三种(因为旋转两次,那么最后最小不平衡子树的根节点为LR,并且LR.bf=EH

1、 LR=EH

旋转之后T.bf=L.bf=EH

2、 LR=LH

旋转之后T.bf=RH, L.bf=EH

3、 LR=RH

旋转之后T.bf=EH, L.bf=LH

代码如下:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>using namespace std;typedef int Status;constexpr auto LH = +1;
constexpr auto EH = 0;
constexpr auto RH = -1;//定义平衡二叉树的节点结构(在二叉排序树中加入一个bf来存储平衡因子)
typedef struct BiTNode
{int data;int bf;struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;void R_Rotate(BiTree* p);
void L_Rotate(BiTree* p);
void LeftBalance(BiTree *T);
void RightBalance(BiTree* T);
void InOrderTraverse(BiTree *T);
Status InsertAVL(BiTree *T,int e,Status *taller);//进行二叉平衡树时的右旋操作
void R_Rotate(BiTree *p)
{BiTree L;L = (*p)->lchild;(*p)->lchild = L->rchild;L->rchild = *p;*p = L;
}//进行二叉平衡树时的左旋操作
void L_Rotate(BiTree *p)
{BiTree R;R = (*p)->rchild;(*p)->rchild = R->lchild;R->lchild = (*p);*p = R;
}//构建二叉平衡树时左边太“重”,进行左平衡处理函数
void LeftBalance(BiTree* T)
{BiTree L, Lr;L = (*T)->lchild;switch (L->bf){/*检查T的左子树的平衡度,并做相应的处理*/case LH:/*新节点插入在了T的左孩子的左子树上,只要做单左旋处理*/(*T)->bf = L->bf = EH;R_Rotate(T);break;case RH:/*新节点插入在了T的左孩子的右子树上,要做双旋处理,通过判断T的左孩子的右子树的根节点的bf来决定进行双旋处理后各自的bf值*/Lr = L->rchild;switch (Lr->bf){case LH:(*T)->bf = RH;L->bf = EH;break;case EH:(*T)->bf = L->bf = EH;break;case RH:(*T)->bf = EH;L->bf = LH;break;}Lr->bf = EH;L_Rotate(&(*T)->lchild);R_Rotate(T);}
}//构建二叉平衡树时右边太“重”,进行右平衡处理函数
void RightBalance(BiTree* T)
{BiTree R, Rl;R = (*T)->rchild;switch (R->bf){/*检查T的右子树的平衡度,并做相应的处理*/case RH:/*新节点插入在了T的右孩子的右子树上,只要做单左旋处理*/(*T)->bf = R->bf = EH;L_Rotate(T);break;case LH:/*新节点插入在了T的右孩子的左子树上,要做双旋处理,通过判断T的右孩子的左子树的根节点的bf来决定进行双旋处理后各自的bf值*/Rl = R->lchild;switch (Rl->bf){case LH:(*T)->bf = EH;R->bf = RH;break;case EH:(*T)->bf = R->bf = EH;break;case RH:(*T)->bf = LH;R->bf = EH;break;}Rl->bf = EH;R_Rotate(&(*T)->rchild);L_Rotate(T);}
}//构建二叉平衡树函数
Status InsertAVL(BiTree* T, int e, Status* taller)
{if (!*T){*T = (BiTree)malloc(sizeof(BiTNode));(*T)->data = e;(*T)->bf = EH;(*T)->lchild = (*T)->rchild = NULL;*taller = true;}else{if (e==(*T)->data){*taller = false;return false;}if (e<(*T)->data){int result = InsertAVL(&(*T)->lchild,e,taller);if (!result){return false;}if (*taller){switch ((*T)->bf){case LH:LeftBalance(T);*taller = false;break;case EH:(*T)->bf = LH;*taller = true;break;case RH:(*T)->bf = EH;*taller = false;break;}}}else{int result = InsertAVL(&(*T)->rchild, e, taller);if (!result){return false;}if (*taller){switch ((*T)->bf){case LH:(*T)->bf = EH;*taller = false;break;case EH:(*T)->bf = RH;*taller = true;break;case RH:RightBalance(T);*taller = false;break;}}}}return true;
}//二叉树中序遍历递归算法
void InOrderTraverse(BiTree* T)
{if (*T==NULL){return;}InOrderTraverse(&(*T)->lchild);cout << (*T)->data << " ";InOrderTraverse(&(*T)->rchild);
}int main()
{int i;int a[10] = {3,2,1,4,5,6,7,10,9,8};BiTree T = NULL;Status Numtaller;for ( i = 0; i < 10; i++){InsertAVL(&T,a[i],&Numtaller);}//中序遍历输出结果InOrderTraverse(&T);
}

本文参考网址

ds查找—二叉树平衡因子_《大话数据结构》C++实现二叉平衡树的建立相关推荐

  1. ds查找—二叉树平衡因子_面试官让我手写一个平衡二叉树,我当时就笑了

    平衡二叉树对于初学者一直是一个比较复杂的知识点,因为其里面涉及到了大量的旋转操作.把大量的同学都给转晕了.这篇文章最主要的特点就是通过动画的形式演示.确保大家都能看懂.最后是手写一个平衡二叉树. 一. ...

  2. DS查找—二叉树平衡因子

    题目描述 二叉树用数组存储,将二叉树的结点数据依次自上而下,自左至右存储到数组中,一般二叉树与完全二叉树对比,比完全二叉树缺少的结点在数组中用0来表示. 计算二叉树每个结点的平衡因子,并按后序遍历的顺 ...

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

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

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

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

  5. 数据结构Java08【二叉平衡树(AVL)-概述、单旋转、双旋转】

    学习地址:[数据结构与算法基础-java版]                  

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

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

  7. 数据结构-树和二叉树(六)二叉平衡树

    本文详细介绍了二叉平衡树的定义.平衡二叉树的插入调整以及查找效率分析! Let's go!

  8. 408数据结构学习笔记——二叉排序树、二叉平衡树、红黑树

    目录 1.二叉排序树 1.1.二叉排序树的基本概念 1.2.二叉排序树的查找代码实现 1.3.二叉排序树的插入 1.4.二叉排序树的删除 1.5.二叉排序树的查找效率 1.6.二叉排序树的缺陷 2.平 ...

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

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

  10. C. DS二叉平衡树构建(教材版)

    [id:157][20分]C. DS二叉平衡树构建 题目描述 在初始为空的平衡二叉树中依次插入n个结点,请输出最终的平衡二叉树. 要求实现平衡二叉树,不可以使用各类库函数. AVL代码参考模板: #i ...

最新文章

  1. Spring 的微内核与FactoryBean扩展机制--转载
  2. 阿里云携手微软与 Crossplane 社区发布 OAM Kubernetes 标准实现与核心依赖库
  3. xfce4开始菜单中的小老鼠图标不见了
  4. C++ 简单的语音合成(TTS,即文字转语音)类
  5. 保留小数点位数和格式
  6. 手把手教你搭建开发环境之Java开发
  7. oracle orapath,SQLNET.ORA中的NAMES.DIRECTORY_PATH设置
  8. django girls_Django Girls Budapest团队的活动筹划技巧
  9. C++ STL中vector的内存机制和性能分析
  10. [听风]TBC炼金速冲1-375
  11. 解决讯飞语音唤醒参数无效(错误码:10106)的问题
  12. win7自动登录(win7自动登录不用输入密码)
  13. Java支付宝订单查询
  14. c语言结构体简单试题,C语言6结构体练习题6
  15. vue-cli 3 跑项目时卡在 ‘98%’ after emitting CopyPlugin 无法运行
  16. c语言lr分析器的设计与实现_ShinyJson实践之路:词法分析器的设计与实现
  17. phaser3适配微信小游戏
  18. 【转帖】暴雪CEO谈魔兽开发:研发团队要对项目有激情
  19. 【自定义控件】仿支付宝支付动画
  20. 阿里云上的高性能高并发高可用架构

热门文章

  1. Ajax:异步JavaScript和XML的笔记略解,不作为知识参考
  2. jQuery简单好用的JavaScript代码库略解使用
  3. 使用html的a标签,无法转跳到servlet页面中的解决办法,适用于servlet的初学者,不与框架相兼容
  4. python管道怎么使用_如何在多个流程中正确使用管道(2)
  5. 群之脉PHP面试,面试问Redis集群,被虐的不行了......
  6. java 三子棋_java三子棋,高手帮忙
  7. C# DateTime的ToString()方法的使用
  8. 算法设计与分析复习——第四章:贪心算法
  9. Exchange企业实战技巧(25)将日历发布到Internet
  10. 大数据时代亟需消除八大“疑云”