不同结构的二叉查找树,查找效率有很大的不同(单支树结构的查找效率退化成了顺序查找)。如何解决这个问题呢?关键在于如何最大限度的减小树的深度。正是基于这个想法,平衡二叉树出现了。

平衡二叉树的定义 (AVL—— 发明者为Adel’son-Vel’skii 和 Landis)

平衡二叉查找树,又称 AVL树。 它除了具备二叉查找树的基本特征之外,还具有一个非常重要的特点:它 的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值(平衡因子 ) 不超过1。 也就是说AVL树每个节点的平衡因子只可能是-1、0和1(左子树高度减去右子树高度)。

那么如何是二叉查找树在添加数据的同时保持平衡呢?基本思想就是:当在二叉排序树中插入一个节点时,首先检查是否因插入而破坏了平衡,若 破坏,则找出其中的最小不平衡二叉树,在保持二叉排序树特性的情况下,调整最小不平衡子树中节点之间的关系,以达 到新的平衡。所谓最小不平衡子树 指离插入节点最近且以平衡因子的绝对值大于1的节点作为根的子树。

平衡二叉树的操作

  • 查找操作
    平衡二叉树的查找基本与二叉查找树相同。

  • 插入操作
    在平衡二叉树中插入结点与二叉查找树最大的不同在于要随时保证插入后整棵二叉树是平衡的。那么调整不平衡树的基本方法就是: 旋转 。 下面我们归纳一下平衡旋转的4种情况:
    这里我们把必须重新平衡的节点叫做A。
    平衡因子:左子树的深度减去右子树的深度。
    相关旋转图示见 严蔚敏《数据结构》(C语言版)P235

    1. 单旋转–向右旋转平衡处理–在A的左儿子的左子树进行一次插入。此时平衡因子变为2。
    2. 单旋转–向左旋转平衡处理–在A的右儿子的右子树进行一次插入操作。此时平衡因子变为-2.
    3. 双旋转–先右后左旋转平衡处理–在A的左儿子的右子树进行一次插入操作。此时平衡因子变为2.
    4. 双旋转–先左后右平衡处理–在A的右儿子的左子树进行一次插入操作。此时平衡因子变为-2.

代码实现:

/***AVL 树 插入新节点 的实现*/struct AVLNode{int val;AVLNode* left;AVLNode* right;int height;AVLNode(const int& value, AVLNode* lt, AVLNode* rt, int h = 0):val(value), left(lt),right(rt),height(h){}
};/***Return thr height of node t ot -1 if NULL* /
int height(AVLNode* t) const
{return t == NULL ? -1 : t->height;
}void insert(const int& x, AVLNode* & t)
{if(t == NULL)   //empty Treet = new AVLNode(x, NULL, NULL);else if(x < t->val)             //插入到左儿子{//insert into left subtreeinsert(x, t->left);if(height(t->left) - height(t->right) == 2){if(x < t->left->val)    //插入到了左儿子的左子树中 ,向右单旋转rotateWithLeftChild(t);else                    //插入到左儿子的右子树, 先左后右双旋转doubleRotateWithLeftChild(t);}}else if(x > t->val)             //插入到右儿子{insert(x, t->right);if(height(t->right) - height(t->left) == 2){if(x > t->right->val)rotateWithRightChild(t);    //插入到右儿子的右子树, 向左单旋转else if(x < t->right->val)doubleRotateWithRightChild(t);  //插入到右儿子的左子树, 先右后左双旋转}}else {//待插入节点已经存在, do nothing}t->height = max(height(t->left), height(t->right)) + 1;
}//向右单旋转
void rotateWithLeftChild( AVLNode* & root)
{AVLNode *newRoot = root->left;root->left = newRoot->right;newRoot->right = root;root->height = max(height(root->left), height(root->right)) + 1;newRoot->height = max(height(newRoot->left), root->height) + 1;root = newRoot;         //root 指向新的root节点
}//向左单旋转
void rotateWithRightChild(AVLNode* & root)
{AVLNode* newRoot = root->right;root->right = newRoot->left;newRoot->left = root;root->height = max(height(root->left), height(root->right)) + 1;newRoot->height = max(height(newRoot->right), root->height) + 1;root = newRoot;
}//先左后右双旋转
void doubleRotateWithLeftChild(AVLNode* & root)
{rotateWithRightChild(root->left);   //先对root的左子树进行向左单旋转rotateWithLeftChild(root);          //然后对root进行向右单旋转
}//先右后左双旋转
void doubleRotateWithRightChild(AVLNode* & root)
{rotateWithLeftChild(root->right);   //先对root的右子树进行向右单旋转rotateWithRightChild(root);         //然后对root进行向左单旋转
}

平衡二叉树性能分析

平衡二叉树的性能优势:
很显然,平衡二叉树的优势在于不会出现普通二叉查找树的最差情况。其查找的时间复杂度为O(logN)。
在平衡树上进行查找的过程和二叉排序树相同,因此,在查找的过程中和给定值进行比较的关键字个数不超过树的深度。
那么,
含有n个关键字的平衡树的最大深度是多少呢?
为了解答这个问题,
可以借助 深度为h的平衡树所具有的最少节点数的计算公式:
最少节点数

S(h) = S(h - 1) + S(h - 2) + 1
其中,h = 0, S(h) = 1;    h = 1, S(h) = 2.

得到h的最大值。

平衡二叉树的缺陷:
(1) 很遗憾的是,为了保证高度平衡,动态插入和删除的代价也随之增加。因此,我们在下一专题中讲讲《红黑树》 这种更加高效的查找结构。

(2) 所有二叉查找树结构的查找代价都与树高是紧密相关的,能否通过减少树高来进一步降低查找代价呢。我们可以通过多路查找树的结构来做到这一点,在后面专题中我们将通过《多路查找树/B-树/B+树 》来介绍。

(3) 在大数据量查找环境下(比如说系统磁盘里的文件目录,数据库中的记录查询 等),所有的二叉查找树结构(BST、AVL、RBT)都不合适。如此大规模的数据量(几G数据),全部组织成平衡二叉树放在内存中是不可能做到的。那么把这棵树放在磁盘中吧。问题就来了:假如构造的平衡二叉树深度有1W层。那么从根节点出发到叶子节点很可能就需要1W次的硬盘IO读写。大家都知道,硬盘的机械部件读写数据的速度远远赶不上纯电子媒体的内存。 查找效率在IO读写过程中将会付出巨大的代价。在大规模数据查询这样一个实际应用背景下,平衡二叉树的效率就很成问题了。对这一问题的解决:我们也会在《多路查找树/B-树/B+树 》 将详细分析。

上面提到的红黑树和多路查找树都是属于深度有界查找树(depth-bounded tree —DBT)

转载于:https://www.cnblogs.com/lanqiu5ge/p/9472203.html

平衡二叉查找树 AVL 的实现相关推荐

  1. C++AVL树(自平衡二叉查找树)(附完整源码)

    C++AVL树自平衡二叉查找树 node结构体定义 实现了以下几个接口 AVL树(自平衡二叉查找树)算法的完整源码(定义,实现,main函数测试) node结构体定义 typedef struct n ...

  2. AVL树-自平衡二叉查找树(Java实现)

    在计算机科学中,AVL树是最先发明的自平衡二叉查找树.AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An alg ...

  3. 构造avl树_图解 AVL 自平衡二叉查找树及 java 实现

    思维导图 AVL树 AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的. 它是最先发明的自平衡二叉查找树(Self-balancing binary sear ...

  4. 平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】...

    平衡树初阶--AVL平衡二叉查找树 一.什么是二叉树 1. 什么是树. 计算机科学里面的树本质是一个树状图.树首先是一个有向无环图,由根节点指向子结点.但是不严格的说,我们也研究无向树.所谓无向树就是 ...

  5. 树的平衡之AVL树——错过文末你会后悔,信我

    学习数据结构应该是一个循序渐进的过程: 当我们学习数组时,我们要体会数组的优点:仅仅通过下标就可以访问我们要找的元素(便于查找). 此时,我们思考:假如我要在第一个元素前插入一个新元素?采用数组需要挪 ...

  6. 为什么红黑树查询快_为什么工程中都喜欢用红黑树,而不是其他平衡二叉查找树呢?...

    前言 二叉查找树是最常用的一种二叉树,它支持快速插入.删除.查找操作,各个操作的时间复杂度跟树的高度成正比,理想情况下,时间复杂度是O(logn). 不过,二叉查找树在频繁的动态更新过程中,可能会出现 ...

  7. 数据结构与算法之美笔记——基础篇(中):树,二叉树,二叉查找树,平衡二叉查找树,红黑树,递归树,堆

    树: A 节点就是 B 节点的父节点,B 节点是 A 节点的子节点.B.C.D 这三个节点的父节点是同一个节点,所以它们之间互称为兄弟节点.我们把没有父节点的节点叫作根节点,也就是图中的节点 E.我们 ...

  8. 红黑树、平衡二叉查找树

    红黑树.平衡二叉查找树 红黑树.平衡二叉查找树 平衡二叉查找树 红黑树 特点 红黑树效率 红黑树和AVL树的比较 红黑树的等价变换 红黑树的操作 旋转操作 左旋 右旋 插入操作 插入操作的所有情况 满 ...

  9. 一看就懂的二叉查找树和平衡二叉查找树

    二叉查找树是一种特殊的二叉树,它可以组织动态数据集合,可以支持数据的快速插入,删除和查找操作.之前我们讨论过哈希表,他的,查找,插如和删除的时间复杂度是O(1),既然哈希表这么高效,那么为什么还需要二 ...

最新文章

  1. 我是如何设计 Upload 上传组件的
  2. JavaScript中处理日期的一些函数和方法
  3. BP神经网络基本原理
  4. matplotlib-pie-绘制饼状图
  5. Redis 命令参考
  6. 下载文件的响应头设置
  7. mysql操作xml字段_SQL XML 字段操作
  8. AUTOSAR从入门到精通100讲(三)-基于UDS服务的BootLoader架构和刷写流程
  9. Windows Mobile 6中禁用键盘或者是禁用某些按键(C#)
  10. vs调试有时能进去后台,有时不能进去
  11. What’s the difference between system.web and system.webServer?
  12. MongoDB Sharding 机制分析
  13. mysql建用户无密码_mysql 新建用户,授权,删除用户,修改密码
  14. (CVPR_2021) Center-based 3D Object Detection and Tracking
  15. html表内画斜线,使用HTML的canvas,给表格画斜线-Go语言中文社区
  16. 报错 proxyconnect tcp: tls: first record does not look like a TLS handshake
  17. j1_8。实现打折功能关键算法。编写程序计算购买图书的总金额。
  18. MySQL详细安装步骤
  19. Centos 7 grub 菜单加密以及取消加密
  20. 网站结构优化要做好哪些

热门文章

  1. 【STM32】DMA程序示例
  2. 【Android】 Android体系结构图
  3. linux中的keeplived源码装,Keepalived高可用集群搭建
  4. java 调度quartz,java quartz任务调度
  5. python mq_RabbitMQPython
  6. java 写文件 0x0d_Java 读写文件 - My and My Princess…… - OSCHINA - 中文开源技术交流社区...
  7. strtol() 字符串转长整型函数
  8. 每天一道LeetCode-----计算整型数二进制中1的个数/返回二进制翻转后的结果
  9. mysql 查询指定字段数据_MySQL使用select语句查询指定表中指定列(字段)的数据
  10. CMake基础 第7节 编译标志