数据结构之“树”——二叉树、红黑树、B树、B+树、B*树

这篇文章主要简单总结下二叉树、红黑树、B树、B+树、B*树的基本结构和原理。

一、二叉树

二叉树就是度不超过2的树(每个结点最多有两个子结点)。
二叉树是有序树(二叉排序树),若将其左右子树颠倒,则成为另一棵不同的二叉树。
二叉树的遍历有三种,分为前序、中序、后序(相对于根节点)。如图:
在这里插入图片描述

根节点-左节点-右节点
左节点-根节点-右节点
左节点-右节点-根节点

1、满二叉树

子节点全满。
在这里插入图片描述

2、完全二叉树

除最后一层外,所有层都是满节点,最后一层所有结点集中在最左边。满二叉树演变而来。
在这里插入图片描述

3、二叉查找树(二叉排序树)

最基础的二叉树是无序的,查询效率极低。排序之后的二叉树为二叉查找树,也是二叉排序树。
二叉查找树:左子树上的节点都小于根节点,右子树上所有节点的值都大于根节点。左、右子树也分别为二叉排序树。
在这里插入图片描述

4、平衡二叉树(AVL树)

在二叉查找树中,任一节点对应的两棵子树的最大高度差为 1,这样的二叉查找树称为平衡二叉树。其中左右子树的高度差也有个专业的叫法:平衡因子。左右节点都得为平衡二叉树。
在这里插入图片描述
平衡二叉树是采用二分查找法思维把数据按规则组装成一个树形结构的数据,用这个树形结构的数据减少无关数据的检索,大大的提升了数据检索的速度。

5、二叉树的左旋、右旋

左旋:是以节点的"右分支"为轴,进行逆时针旋转。
右旋:是以节点的“左分支"为轴,进行顺时针旋转。
在这里插入图片描述
为了达到平衡,二叉树会进行旋转操作。----一旦由于插入或删除导致左右子树的高度差大于1,此时就需要旋转某些节点调整树高度,使其再次达到平衡状态,这个过程称为旋转再平衡。

二、红黑树

红黑树也是一种特殊的二分查找树,但是红黑树是可以不让树频繁的去旋转平衡,归根结底就一句话:
最长子树只要不超过最短子树的两倍就OK,添加了变色的行为来保证树的平衡
具体要求如下:

①每个节点或者是黑色,或者是红色。
②根节点是黑色。
③每个叶子节点(NIL)是黑色。[注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点]
④如果一个节点是红色的,则它的子节点必须是黑色的。
⑤从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。[这里指到叶子节点的路径]

如图:
在这里插入图片描述
红黑树的插入操作如下:
首先是先插入;插入后,以刚插入的节点作为当前平衡节点N,进行平衡操作。
图解如下:
在这里插入图片描述

三、B树

B树和平衡二叉树稍有不同的是B树属于多叉树又名平衡多路查找树(查找路径不只两个),数据库索引技术里大量使用B树和B+树的数据结构。
B树属性如下:

每一个节点最多有 m 个子节点
每一个非叶子节点(除根节点)最少有 ⌈m/2⌉ 个子节点,⌈m/2⌉表示向上取整。
如果根节点不是叶子节点,那么它至少有两个子节点
有 k 个子节点的非叶子节点拥有 k − 1 个键
所有的叶子节点都在同一层

我们拿数据库索引来看,先看图:
在这里插入图片描述
这是典型的B树了,以查22为例,查询流程如下;
1、根节点查询,读入第一次内存(1次磁盘I/O);
2、区间为13-35,找到磁盘1的指针p2,可以找到磁盘3,读入第二次内存(2次磁盘I/O);
3、区间为20-33,找到磁盘3的指针p2,可以找到磁盘7,读入第三次内存(3次磁盘I/O);
4、在磁盘7中找到22。
大致流程如上,但是随之而来的缺点也很明显:
1、每个节点都存储data,磁盘大小有限,data大的话,会导致存储的数据有限。
2、数据数量比较多的时候,树的深度会变大,I/O次数会增加。

InnoDB 这种存储引擎默认情况下读的是 16kb,一共读取了三个磁盘块,意味着一共读取了 48k 的数据,假如说上面的这些 p 指针和 16 这些 key 值都不需要占用额外的存储空间,一条数据占用 1kb 的空间,那意味着当前节点里面最多存 16 条数据,下一个磁盘块也是 16 条,第三个磁盘块也是 16 条,计算一下的话是 16×16×16,也就是 4096 条数据。这个支撑的数据量也太少了。在生产环境中随便的一个 mysql 表都要上百万条,不可能是只有几万或者几千,这不太可能,这时候就要思考 b 树有什么问题了。

四、B+树

为了解决以上问题,引入了B+树。
在这里插入图片描述
如图所示,数据存储再叶子节点中,这样就不会造成存储空间有限的问题了。

读取的数据还是 16kb、16kb、16kb,假设,key 值加上 p 指针一共占用 10 个字节,那么 16kb 就是是 16×1000/10,得到结果为 1600,第二层也是 1600,第三层还是 16,所以最终的结果为 40960000 条数据,达到千万级别。而刚刚 B 树是 4096,完全不是一个量级。 因此,在三到四层的 B+树中,基本可以支持千万级别数据量的存储。

MySQL用的就是B+树。

五、B*树

是B+树的变体,在B+树的非根和非叶子结点再增加指向兄弟的指针。
在这里插入图片描述

B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3(代替B+树的1/2);

B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;
B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针。

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
http://www.400gb.com/u/256394 译者序 前言 致谢 第1章 绪论  1.1 评估算法  1.2 修改算法   1.2.1 主要的优化:I/O   1.2.2 主要的优化:函数调用  1.3 资源和参考资料 第2章 基本数据结构  2.1 链表   2.1.1 双向链表   2.1.2 链表的其他特征  2.2 栈和队列   2.2.1 栈的特征   2.2.2 队列的特征 第3章 散列  3.1 散列的概念  3.2 散列函数  3.3 冲突解决方法   3.3.1 线性再散列法   3.3.2 非线性再散列法   3.3.3 外部拉链法  3.4 性能问题  3.5 资源和参考资料 第4章 查找  4.1 查找的特征   4.1.1 准备时间   4.1.2 运行时间     4.1.3 回溯的需要  4.2 蛮力查找  4.3 Boyer Moore查找   4.3.1 启发式方法#1:跳过字符   4.3.2 启发式方法#2:重复模式  4.4 多字符串查找  4.5 用于正则表达式的字符串查找:grep  4.6 近似字符串匹配技术  4.7 语音比较:Soundex算法  4.8 Metaphone:现代的Soundex  4.9 选择技术  4.10 资源和参考资料   4.10.1 通用参考资料   4.10.2 Boyer Moore   4.10.3 多字符串查找   4.10.4 正则表达式查找   4.10.5 近似字符串匹配   4.10.6 Soundex算法和Metaphone算法 第5章 排序  5.1 排序的基本特征   5.1.1 稳定性   5.1.2 对哨兵的需求   5.1.3 对链表进行排序的能力   5.1.4 输入的阶的相关性   5.1.5 对额外存储空间的需求   5.1.6 内部排序技术与外部排序技术  5.2 排序模型   5.2.1 冒泡排序   5.2.2 插入排序   5.2.3 希尔排序   5.2.4 快速排序   5.2.5 堆排序  5.3 对链表进行插入排序  5.4 对链表进行快速排序  5.5 对多个键进行排序——不稳定排序的修正方法  5.6 网络排序  5.7 小结:选择一种排序算法  5.8 资源和参考资料 第6章   6.1 二叉树   6.1.1 查找   6.1.2 节点插入   6.1.3 节点删除   6.1.4 二叉查找的性能   6.1.5 AVL  6.2 红黑树  6.3 伸展  6.4 B树   6.4.1 保持B树平衡   6.4.2 实现B树算法   6.4.3 B树实现的代码  6.5 可以看见森林吗  6.6 资源和参考资料 第7章 日期和时间  7.1 日期例程的库  7.2 时间例程  7.3 用于日期和时间数据的格式  7.4 最后的提醒  7.5 资源和参考资料 第8章 任意精度的算术  8.1 构建计算器8.2表示数字  8.3 计算  8.4 加法  8.5 减法  8.6 乘法  8.7 除法  8.8 关于计算器要注意的最后几点  8.9 用于计算平方根的牛顿算法  8.10 分期付款表  8.11 资源和参考资料 第9章 数据压缩  9.1 行程编码  9.2 霍夫曼压缩   9.2.1 代码   9.2.2 其他问题  9.3 滑动窗口压缩  9.4 基于字典的压缩(LZW)   9.4.1 LZW算法的伪代码   9.4.2 LZW压缩的实现   9.4.3 填满字典  9.5 使用哪种压缩方法  9.6 资源和参考资料 第10章 数据完整性和验证  10.1 简单的校验和  10.2 加权校验和  10.3 循环冗余校验   10.3.1 CRC CCITT   10.3.2 CRC 16   10.3.3 CRC 32   10.4 资源和参考资料
第1章向读者介绍数据结构作为数据集合的概念。介绍线性和非线性集合的概念。示范说明了Collection类。本章还介绍泛型编程的概念。泛型编程允许程序员编写一个类或一种方法,并且把它用于众多数据类型。泛型编程是C#语言一种重要的新特性(在C#2.0以及更高版本中可用)。这种特性是如此重要以至于在System.Collections.Generic命名空间中存在一个专门的泛型数据结构库。当数据结构具有在此库中能找到的泛型实现时,就会讨论它的用途。本章结尾处介绍了衡量书中讨论的数据结构算法性能的方法。 第2章提供了数组构造方法的回顾,并连同示例说明了Array类的特征。Array类把许多与数组相关的函数(UBound函数、LBound函数等等)封装到单独一个包中。ArrayLists是数组的一种特殊类型,它支持动态地调整容量。 第3章是对基础排序算法的介绍,例如冒泡排序和插入排序。而第4章则研究了用于内存查找的最基本算法,顺序查找和二叉查找。 第5章探讨了两种经典的数据结构:堆栈和队列。本章节强调的重点是这些数据结构在解决日常数据处理问题中的实际应用。第6章讲述了BitArray类。这种类可以用于有效地表示大量整数值,比如测试成绩。 数据结构的书中通常不包含字符串,但是第7章介绍了字符串、String类和StringBuilder类。这是因为在C#语言中许多的数据处理是在字符串上执行的,读者应该接触基于这两种类的特殊方法。第8章分析了用于文本处理和模式匹配的正则表达式的使用。与较传统的字符串函数和方法相比,正则表达式常常会提供更强大更有效的处理。 第9章向读者介绍作为数据结构的字典的使用。字典和基于字典的不同数据结构把数据作为键/值对来存储。本章向读者说明了如何创建基于DictionaryBase类的他或她自己的类。DictionaryBase类是一个抽象类。第10章包括散列表和HashTable类。HashTable类是字典的一种特殊类型,它用散列算法对内部数据进行存储。 链表作为另外一种经典的数据结构是在第11章介绍。链表在C#语言中不像在C++这样基于指针的语言中那样重要,但是它始终在C#编程中发挥作用。第12章为读者介绍另一种经典数据结构——二叉树。二叉查找作为二叉树的特殊类型将是本章的主要内容。其他二叉树类型在第15章进行介绍。 第13章向读者说明在集合中存储数据的方法。这种方法在数据结构只存储唯一数据值的情况下是很实用的。第14章涵盖了高级排序算法,包括流行且高效的快速排序算法。此算法是大多数在.NET框架库中实现的排序程序的基础。第15章会看到三种数据结构。在无法使用二叉查找的时候,这三种数据结构证明对查找是很有用的。他们是:AVL红黑树和跳跃表。 第16章讨论了图以及图的算法。图在表示许多不同的数据类型时非常有用,特别是网络的情况。最后,第17章向读者介绍真正的算法设计技巧是什么:动态算法和贪心算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值