1.概念

平衡二叉树(AVL Tree)首先要满足二叉树的定义,如下

  • 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
  • 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 左、右子树也分别为二叉排序树;
  • 没有键值相等的节点。
  • 平衡度是左子树高度减去右子树高度,平衡度只能是-1,+1,0
下图给出了一个非平衡二叉排序树和平衡二叉排序树
说明:结点上方的数字是平衡度(平衡因子),a图9结点左子树比右子树高2,不满足AVL Tree的定义,所以是非平衡树
b图所有结点度数绝对值没有超过1,所以满足平衡树的定义,是平衡树
  • 危机结点是指平衡度为1,有可能破坏平衡树的结点
  • 左改组是指新结点插入到危机结点的左树下
  • 右改组是指新新结点插入到危机结点的右子树下
  • LL是新结点插入在危机节点的左子树的左子树上
  • LR是新结点插入在危机节点的左子树的右子树上
  • RR是新结点插入在危机节点的右子树的右子树上
  • RL是新结点插入在危机节点的右子树的左子树上

2.代码实现

当前树的结构

11
          /   \
        7       15
       / \    /  \
      3      9  14      18
     / \     /    / \
    1   5    12   16     20
                     /
                   26

2.1 定义平衡树结点:

平衡因子可以是右子树高度减去左子树高度,不同的教材定义不一样,我这里按照左树-右树来做

template<class K, class V>
struct AVLTreeNode
{K _key;                //树权值
    V _value;int  _bf;            //平衡因子 -1,0,1        (每个节点的平衡因子等于左子树的高度减去右子树的高度) //有的教材定义平衡度是左子树高度减去右子树,都是可以的AVLTreeNode<K, V>* _parent;    //指向父节点的指针AVLTreeNode<K, V>* _left;            //指向左孩子的指针AVLTreeNode<K, V>* _right;        //指向右孩子的指针
AVLTreeNode(const K& key = K(), const V& value = V()):_key(key), _value(value), _bf(0), _parent(NULL), _left(NULL), _right(NULL){}
};

2.2 左改组图解

左右改组是为了方便我们插入删除的时候保持二叉树平衡而引入的概念

左改组LL型和LR(a),LR(b),LR(c)型图解

2.3 左改组LL型

首先声明一个构造的左子树,subL其实就是危机结点,subLR是危机节点的右子树,ppNode是祖先节点

构建parent子树,将parent和subL连接起来

如果祖先结点为空,将当前结点subL置为根节点,请参见上图(a‘)的情况,B是危机结点,调整过后变成了根节点

否则祖父结点赋给subL的父结点,判断父节点是否是祖先结点的左子树,是的话,用构造的左子树替代之

不是就用subL替代祖先节点的右子树

//左改组LL型
template<class K, class V>
void AVLTree<K, V>::_RotateLL(AVLTreeNode<K, V>*&  parent)
{AVLTreeNode<K, V>* subL = parent->_left; //构造的左子树AVLTreeNode<K, V>* subLR = subL->_right;//subL的右子树AVLTreeNode<K, V>* ppNode = parent->_parent;//标记祖先节点//1.构建parent子树 将parent和subLR链接起来parent->_left = subLR;if (subLR) subLR->_parent = parent;//2.构建subL子树 将subL与parent链接起来subL->_right = parent;parent->_parent = subL;//3.将祖先节点与subL链接起来if (ppNode == NULL){    //如果祖先为NULL,说明当前subL节点为根节点subL->_parent = NULL;_root = subL;}else{subL->_parent = ppNode;if (ppNode->_left == parent)ppNode->_left = subL;else if (ppNode->_right == parent)ppNode->_right = subL;}//4.重置平衡因子parent->_bf = 0;subL->_bf = 0;//5.更新subL为当前父节点parent = subL;
}

2.4 左改组LR(a)、LR(b)和LR(c)型

pNode是当前父节点,subR是构造的右子树,subLR是subR的左子树

对当前父节点LL左改组,再右改组

根据平衡因子判断是LR什么类型,请参见上图图解(b),(c),(d)的情况

//左改组LR型
template<class K, class V>
void AVLTree<K, V>::_RotateLR(AVLTreeNode<K, V>*&  parent)
{AVLTreeNode<K, V>* pNode = parent;AVLTreeNode<K, V>* subR = parent->_right;AVLTreeNode<K, V>* subLR = subR->_left;int bf = subLR->_bf;_RotateLL(parent->_right);_RotateRR(parent);//LR(b)型if (bf == -1){pNode->_bf = 0;subR->_bf = 1;}//LR(a)型else if (bf == 1){pNode->_bf = -1;subR->_bf = 0;}//LR(c)型else{pNode->_bf = 0;subR->_bf = 0;}
}

右改组和左改组镜像对称,反过来就行了

2.5 插入函数

AVL树是空,将当前结点直接置为根节点

AVL树在满足平衡度的要求下,和二叉排序树一致,key小于当前结点,转到当前结点左子树,key大于当前结点,转到当前结点右子树

将parent的左子树赋予当前结点,更新平衡因子,_bf++

将parent的右子树赋予当前结点,更新平衡因子,_bf--

如果合法,即平衡因子=0,终止当前循环

如果当前结点是危机结点,即平衡度绝对值等于1,当前结点往上回溯,变成父节点,继续检查它的平衡度

接下来是平衡异常的情况,父结点平衡度为2,当前结点(危机结点)平衡度为1,进入左改组LL,LL介绍参考2.2 左改组LL

当前结点平衡度为-1,进入左改组LR,LR介绍参考2.3 左改组LR

右改组的情况类似

template<class K, class V>
bool AVLTree<K, V>::Insert(const K& key, const V& value)
{//1.空树if (_root == NULL){_root = new AVLTreeNode<K, V>(key, value);return true;}//2.AVL树不为NULLAVLTreeNode<K, V>* parent = NULL;AVLTreeNode<K, V>* cur = _root;//找到数据插入位置while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}//插入数据cur = new AVLTreeNode<K, V>(key, value);cur->_parent = parent;if (parent->_key > key)parent->_left = cur;elseparent->_right = cur;while (parent){//更新平衡因子if (cur == parent->_left)parent->_bf++;else if (cur == parent->_right)parent->_bf--;//检验平衡因子是否合法if (parent->_bf == 0)break;else if (parent->_bf == -1 || parent->_bf == 1){    // 回溯上升 更新祖父节点的平衡因子并检验合法性cur = parent;parent = cur->_parent;}//    2 -2 平衡因子不合法 需要进行旋转 降低高度else   {if (parent->_bf == -2){if (cur->_bf == -1)_RotateRR(parent);else_RotateLR(parent);}else if (parent->_bf == 2){if (cur->_bf == 1)_RotateLL(parent);else_RotateRL(parent);}break;}}
}

2.6 遍历方法

//中序遍历
template<class K, class V>
void AVLTree<K, V>::_InOrder(AVLTreeNode<K, V>* root)
{if (root == NULL)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);
}
//前序遍历
template<class K, class V>
void AVLTree<K, V>::_PreOrder(AVLTreeNode<K, V>* root)
{if (root == NULL)return;cout << root->_key << " ";_PreOrder(root->_left);_PreOrder(root->_right);
}
//后序遍历
template<class K, class V>
void AVLTree<K, V>::_PostOrder(AVLTreeNode<K, V>* root)
{if (root == NULL)return;_PostOrder(root->_left);_PostOrder(root->_right);cout << root->_key << " ";
}

3.运行和源码

运行效果如下

源代码:https://github.com/cjy513203427/C_Program_Base/tree/master/61.%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91/61.%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91

转载于:https://www.cnblogs.com/Java-Starter/p/10192034.html

C++实现平衡二叉树相关推荐

  1. java avl_Java底层实现AVL 平衡二叉树

    1.为什么要有AVL平衡二叉树 我们之前写过文章叫做BST二分搜索树,这种数据结构有一个缺点就是会退化为链表形式,到这导致了我们的树结构发挥不出来它应有的优势. 从上图可以发现如果按照顺序进行添加操作 ...

  2. python实现平衡二叉树_LeetCode 110. 平衡二叉树 | Python

    # 110. 平衡二叉树 --- 题目来源:力扣(LeetCode)[https://leetcode-cn.com/problems/balanced-binary-tree](https://le ...

  3. mysql 索引 二叉树_MySQL 的索引,为什么是 B+而不是平衡二叉树

    数据库为什么使用 B+ 树? 前言 讲到索引,第一反应肯定是能提高查询效率.例如书的目录,想要查找某一章节,会先从目录中定位.如果没有目录,那么就需要将所有内容都看一遍才能找到. 索引的设计对程序的性 ...

  4. 普通二叉树、二叉查找树、平衡二叉树常见操作汇总

    目录 总览表 普通二叉树 二叉查找树 平衡二叉树 总览表 普通二叉树 struct Node{int data;Node* lchild,rchild; };Node* newNode(int v){ ...

  5. 剑指Offer——平衡二叉树

    题目描述: 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 分析: 平衡二叉树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质 ...

  6. 【每日一算法】平衡二叉树

    微信改版,加星标不迷路! 每日一算法-搜索插入位置 作者:阿广 阅读目录 ? 题目 ? 解析 ? 完整代码 1 题目 给定一个二叉树,判断它是否是高度平衡的二叉树. 本题中,一棵高度平衡二叉树定义为: ...

  7. 带父节点的平衡二叉树_学习数据结构--第四章:树与二叉树(平衡二叉树)

    第四章:树与二叉树(平衡二叉树) 1.平衡二叉树 平衡二叉树:AVL,任意结点的平衡因子的绝对值不超过一. 平衡因子:左子树高度 - 右子树高度 如上图二叉树,是否是平衡二叉树? 可以把所有结点的平衡 ...

  8. java TreeMap 源代码分析 平衡二叉树

    TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 TreeMap 的关系 为了让大家了解 TreeMap 和 Tre ...

  9. python判断二叉树是否为平衡二叉树

    python判断二叉树是否为平衡二叉树 树是数据结构中的重中之重,尤其以各类二叉树为学习的难点.一直以来,对于树的掌握都是模棱两可的状态,现在希望通过写一个关于二叉树的专题系列.在学习与总结的同时更加 ...

  10. 高度平衡二叉树的构建_平衡二叉树(AVL)树

    1.平衡二叉树定义 是一种二叉排序树(二叉查找树.二叉搜索树),其中每个节点的左子树和右子树的高度差不大于1.(左右子树也是平衡二叉树) 平衡因子BF = 二叉树节点的左子树深度减去右子树深度 = 节 ...

最新文章

  1. 低调的,我们改名字了!
  2. [Android]Android端ORM框架——RapidORM(v1.0)
  3. 戴尔服务:为企业转型导航
  4. 初学者如何学习Vim
  5. 洛谷P3773 [CTSC2017]吉夫特(Lucas定理,dp)
  6. 三体智能革命_《三体》之人类的科技文明发展历史其实很诡异
  7. 分分钟手写http server
  8. python常用运维模块_python常用模块之一
  9. Android深入浅出之Binder机制(转)
  10. [Elasticsearch] es 6.8 编译报错 invalid type code: 85
  11. ibm量子计算机 申请,【IBM量子计算机问世,造福人类的杰作!】IBM量子计算机已面前全球开放申请使用_来自网易大神圈子_科学企图玄学...
  12. python入门_老男孩_数据类型简介_int/bool/str转换_字符串索引和切片_字符串操作_day3...
  13. 如何为SharePoint添加一个简单地SMTP邮件发送服务器?
  14. Intellij IDEA配置优化--转载
  15. 将beyond compare设置为svn的代码比较工具
  16. Android 热修复原理
  17. android addr2line使用
  18. 微信支付商户平台,企业付款,企业向个人付款接口总结
  19. Serverless 极致弹性解构在线游戏行业痛点,你有过迷茫吗
  20. 《天天数学》连载62:三月二日

热门文章

  1. DAY4-打卡第四天-2018-1-12
  2. Ansible之八:Playbook循环
  3. JS实现转动随机数抽奖的特效代码
  4. 初探swift语言的学习笔记五(线程)
  5. Safari下弹窗问题的解决办法
  6. ***帮兄设计实战分析
  7. Django_ORM数据表查询总结
  8. 关于对FLASH开发,starling、starling feathers、starling MVC框架的理解
  9. Android handler Thread 修改UI Demo
  10. Unix时间戳转换(python)