个恐怕是整个《数据结构》教科书里面最难的和最“没用”的数据结构了(现在的教科书还有部分算法内容)。说它没用,恰恰是因为它太有用——有着和普通的二

叉搜索树完全一样的接口界面,绝大多数情况下比普通的二叉搜索树效率高(很多)。因此,通常情况下,人们都是一劳永逸的——写完后就重用,而不会再写了。

所以说,你虽然学完了平衡二叉树,但很可能你永远也不会亲自写一个。你现在随便在身边拉个人,让他来写一个,能顺利的写出来的恐怕不多,玩笑之词,且勿当

真。

在开始写之前,我很担心,能不能把这部分写清楚,毕竟书上满天的switch…case,并且还只是一半——有左旋没有右旋,有插入没有删除。后来,我变得有信心了——因为书上都没有说清楚,都在那里说梦话。我没有找到AVL树的发明者的原著(G. M. Adelson-Velskii and Y. M. Landis. An algorithm for the organization of information. Soviet Math. Dokl., 3:1259--1262, 1962.)也不知道我下面所写的是不是体现了发明者的本意,但至少,我认为现在的教科书歪曲了发明者的本意。

基本概念

Ø平衡

下面的引文出自Algorithms and Data Structures(Niklaus Wirth, Prentice-Hall, Englewood Cliffs, NJ, 1986 ISBN: 0-13-022005-1 pp. 215 – 226)

One such definition of balance has been postulated by Adelson-Velskii and Landis [4-1]. The balance criterion is the following:

A tree is balancedif and only if for every node the heights of its two subtrees differ by at most 1.

Trees satisfying this condition are often called AVL-trees (after their inventors). We shall simply call them balanced treesbecause this balance criterion appears a most suitable one. (Note that all perfectly balanced trees are also AVL-balanced.)

The definition is not only simple, but it also leads to a manageable rebalancing procedureand an average search path length practically identical to that of tbe perfectly balanced tree.

科技文都比较好懂,本人翻译水平比较差,就不献丑了,我只想让大家注意最后一段的画线部分,平衡化应该是易于操作的,而绝不是现在你在书上看到的铺天盖地的switch…case。

Ø旋转

平衡化靠的是旋转。参与旋转的是3个节点(其中一个可能是外部节点NULL),旋转就是把这3个节点转个位置。注意的是,左旋的时候p->right一定不为空,右旋的时候p->left一定不为空,这是显而易见的。

p

p

p

左旋

t

t

(p)

(NULL)

(NULL)

可以看到,左旋确实是在向“左”旋转,还是很形象的。右旋是左旋的镜像,就不再另行说明了。下表是左旋和右旋各个节点的指针变换情况。(括号表示NULL的情况不执行)

左旋

右旋

t->parent = p->parent

p->parent = t

t->parent = p->parent

p->parent = t

(t->left->parent = p)

p->right = t->left

(t->right->parent = p)

p->left = t->right

t->left = p

p = t

t->right = p

p = t

Ø平衡因子(bf——balance factor)

AVL树的平衡化靠旋转,而是否需要平衡化,取决于树中是否出现了不平衡。为了避免每次判断平衡时,都求一下左右子树的高度,引入了平衡因子。很可能是1962年的时候AV&L没有亲自给出定义,时下里平衡因子的定义乱七八糟——我看了4本书,两本是bf= 左高-右高,两本是bf= 右高-左高。最有意思的是两本中国人(严蔚敏和殷人昆)写的一本左减右,一本右减左;两本外国人写的也是这样。虽然没什么原则上的差别,可苦了中国的莘莘学子们——考试的时候可不管你是哪个门派的。我照顾自己的习惯,下面的bf =左高-右高,习惯不同的请自己注意。

这样一来,是否需要平衡化的条件就很明了了——| bf | > 1。如果从空树开始建立,并时刻保持平衡,那么不平衡只会发生在插入删除操作上,而不平衡的标志就是出现bf == 2或者bf == -2的节点。

插入和删除

在AVL树插入和删除,实际上就是先按照普通二叉搜索树插入和删除,然后再平衡化。可以肯定的说,插入和删除需要的最多平衡化次数不同(下面会给出根本原因),但这不表明插入和删除时的平衡化的思路有很大差别。现有的教科书,仅仅从表面上看到了到了平衡化操作次数不同的假象,而没有从根本上认识到插入和删除对称的本质,搞得乱七八糟不说(铺天盖地的switch…case),还严重的误导了读者——以为删除操作复杂的不可捉摸。

AVL树体现了一种平衡的美感,两种旋转是互为镜像的,插入删除是互为镜像的操作,没理由会有那么大的差别。实际上,平衡化可以统一的这样来操作:

1.while (current != NULL)修改current的平衡因子。

Ø插入节点时current->bf += (current->data > *p)?1:-1;

Ø删除节点时current->bf -= (current->data > *p)?1:-1;

Øcurrent指向插入节点或者实际删除节点的父节点,这是普通二叉搜索树的插入和删除操作带来的结果。*p初始值是插入节点或者实际删除节点的data。因为删除操作可能实际删除的不是data。

2.判断是否需要平衡化

if (current->bf == -2) L_Balance(c_root); else if (current->bf == 2) R_Balance(c_root);

3.是否要继续向上修改父节点的平衡因子

Ø插入节点时if (!current->bf) break;这时,以current为根的子树的高度和插入前的高度相同。

Ø删除节点时if (current->bf) break;这时,以current为根的子树的高度和删除前的高度相同

Ø之所以删除操作需要的平衡化次数多,就是因为平衡化不会增加子树的高度,但是可能会减少子树的高度,在有有可能使树增高的插入操作中,一次平衡化能抵消掉增高;在有可能使树减低的删除操作中,平衡化可能会带来祖先节点的不平衡。

4.当前节点移动到父节点,转1

p = &(current->data); current = current->parent;

完整的插入删除函数如下:

bool insert(const T &data)

{

if (!BSTree::insert(data)) return false; const T* p = &data;

while (current)

{

current->bf += (current->data > *p)?1:-1;

if (current->bf == -2) L_Balance(c_root);

else if (current->bf == 2) R_Balance(c_root);

if (!current->bf) break;

p = &(current->data); current = current->parent;

}

return true;

}

bool remove(const T &data)

{

if (!BSTree::remove(data)) return false; const T* p = &r_r_data;

//在class BSTree里添加proteceted: T r_r_data,在BSTree::remove(const T &data)里修改为实际删除的节点的data

while (current)

{

current->bf -= (current->data > *p)?1:-1;

if (current->bf == -2) L_Balance(c_root);

else if (current->bf == 2) R_Balance(c_root);

if (current->bf) break;

p = &(current->data); current = current->parent;

}

return true;

}

你可以看到,他们是多么的对称。

对称二叉树c++_数据结构学习(C++)——平衡二叉树相关推荐

  1. 对称二叉树c++_二叉树:我对称么?

    给「代码随想录」一个星标吧! ❝ 又是一道"简单题"? ❞ 101. 对称二叉树 给定一个二叉树,检查它是否是镜像对称的. 思路 「首先想清楚,判断对称二叉树要比较的是哪两个节点, ...

  2. noj数据结构稀疏矩阵的加法十字链表_数据结构学习(C )稀疏矩阵(十字链表1)

    CSDN 先说说什么叫稀疏矩阵. 你说, 这个问题很简单吗, 那你一定不知道中国学术界的嘴皮子仗, 对一个字眼的"抠"将会导致两种相反的结论.这是清华 2000 年的一道考研题:& ...

  3. 人们通常先在线性表尾部临时添加一个_数据结构学习笔记-线性表

    我们经常会处理一系列类型相同的数据, 创建这种元素组, 读取和修改 当我们处理一个具有有穷或者无穷的元素数据集的时候, 我们需要将其作为一个整体来管理和使用, 用变量去表示它们, 传入和传出函数等等. ...

  4. 数据结构java学生成绩排序_数据结构学习--Java简单排序

    冒泡排序需要元素每次遍历都从最底部向上冒泡,找到适合的位置后,该位置之后的元素继续向上冒,这样一趟排序结束后,将冒出最大或者最小值. 选择排序需要元素从0号位开始向上遍历一遍,并将最小值放到0号位上, ...

  5. 数据结构学习笔记(六):二叉树(Binary Tree)

    目录 1 背景知识:树(Tree) 2 何为二叉树(Binray Tree) 2.1 二叉树的概念与结构 2.2 满二叉树与完全二叉树 2.3 二叉树的三种遍历方式 3 二叉树及其遍历的简单实现(Ja ...

  6. 【二叉树相关习题】二叉树最大深度;平衡二叉树;最近公共祖先;对称二叉树;

    二叉树相关习题 文章目录 二叉树相关习题 1. 检查两棵树是否相同 2. 判断一个树是否是另一个树的子树 3. 二叉树的最大深度 4. 判断一颗二叉树是否是平衡二叉树 5. 对称二叉树 6. 二叉树的 ...

  7. 邓俊辉数据结构学习笔记3-二叉树

    二叉树及其表示 树 有根树 从图论的角度看,树等价于连通无环图.因此与一般的图相同,树也由一组项点〈vertex)以及联接与其间的若干条边〈edge) 组成.在计算机科学中,往往还会在此基础上,再指定 ...

  8. 数据结构学习笔记(王道)

    数据结构学习笔记(王道) PS:本文章部分内容参考自王道考研数据结构笔记 文章目录 数据结构学习笔记(王道) 一.绪论 1.1. 数据结构 1.2. 算法 1.2.1. 算法的基本概念 1.2.2. ...

  9. 代码随想录算法训练营第十五天| 102层序遍历、226.翻转二叉树、101. 对称二叉树

    层序遍历 参考文章:代码随想录 解题思路: 层序遍历一个二叉树.就是从左到右一层一层的去遍历二叉树.这种遍历的方式和我们之前讲过的都不太一样. 需要借用一个辅助数据结构即队列来实现,队列先进先出,符合 ...

最新文章

  1. Pandownload惊喜复活!下载速度惊人!
  2. Leetcode1703. 得到连续 K 个 1 的最少相邻交换次数[C++题解]:难(货仓选址加强版+滑动窗口+前缀和)
  3. cornerstone的简单使用
  4. java窗体添加背景图片_Java项目实战之实战之天天酷跑(四):游戏主界面
  5. 前端学习(16):跳转链接小练习
  6. 报表中Mail Label 的使用
  7. java foxpro_java解析FoxPro DBF数据文件
  8. 记录——《C Primer Plus (第五版)》第八章编程练习第六题
  9. 搭建LAMP架构之Apache2.4.4安装及管理
  10. Jquery 提交 乱码的问题
  11. VS2013+cuda8.0配置及案例
  12. 管理感悟:开会为什么坐到后面
  13. keil+flymcu+CubeMX开发STM32F407
  14. IDEA导入jar包之后引用不了
  15. Leetcode520Detect Capital检测大写字母
  16. c++系列:关于MSVCR100.dll、MSVCR100d.dll、Msvcp100.dll、Msvcp100D.dll 故障查及解决方法
  17. 无线鼠标vs蓝牙鼠标
  18. 计算机word中的行间距在哪里设置,word怎么把所有行间距设置成22磅
  19. 使用语义分割架构的文档扫描仪 DeepLabV3
  20. 详述数据中心内部通风的几种形态

热门文章

  1. Laravel 生成二维码的方法
  2. Unity Standard Assets Example Project
  3. 数据驱动测试之——CSV+TestNG
  4. WinForm 快捷键设置
  5. jquery实现无刷新分页,跳转
  6. windows server 2008中IIS7的功能模塊
  7. 前端调数据会经常用到的事件处理
  8. (转载)二进制与三进制的妙用
  9. windows下PostgreSQL 安装与配置
  10. php函数引用参数解惑《细说php》