树相关学习笔记

二叉树

  1. 二叉树是每个节点最多有两个子节点的树。
  2. 二叉树的叶子节点有0个子节点,二叉树的根节点或者内部节点有一个或者两个子节点。

    先序遍历:根左右。

    中序遍历:左根右。

    后序遍历:左右根。

先序遍历:1、2、4、5、7、3、6。

    中序遍历:4、2、7、5、1、3、6。

    后序遍历:4、7、5、2、6、3、1。

二叉搜索(查找、排序)树:

    1.若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值

    2.若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值

    3.它的左右子树也分别为二叉搜索树。

    4.通过中序遍历得到的序列是有序的

平衡二叉树(AVL树,它是基于二叉排序树的一种树,二叉排序树极端情况下可能成为一个链表,AVL树确保了左右子树的平衡,方便查找):

    1.它是一颗空树或它的左右子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树。

红黑树(R-B Tree,自平衡的二叉查找树):

    它是一种特殊的二叉查找树,红黑树的每个节点上都有存储位表示节点的颜色,可以使红或黑。

    1. 每个节点是红或者黑

    2. 根节点是黑色

    3. 每个叶子节点(NIL)是黑色。(这里的叶子节点只指为空的叶子节点)。

    4. 如果一个节点是红色,则它的子节点必须是黑色的。

    5.从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点

      红黑树并不是一个完美的平衡二叉查找树,上图可以看出,根节点P的左子树显然比右子树高,但左子树和右子树的黑节点的层数是相等的,也即性质5.所以我们叫红黑树这种平衡为黑色完美平衡。

红黑树总是通过旋转和变色达到自平衡

旋转:https://www.jianshu.com/p/e136ec79235c

    红黑树查找:

     1.从根结点开始查找,把根结点设置为当前结点;

     2.若当前结点为空,返回null;

     3.若当前结点不为空,用当前结点的key跟查找key作比较;

     4.若当前结点key等于查找key,那么该key就是查找目标,返回当前结点;

     5.若当前结点key大于查找key,把当前结点的左子结点设置为当前结点,重复步骤2;

     6.若当前结点key小于查找key,把当前结点的右子结点设置为当前结点,重复步骤2。



 

B树(也叫B-树),例如一颗m阶的B树,需要满足的条件:

        首先说下m阶,并不是说有m层,而是说一个节点最多能有m个子节点,也就是每个节点上最多有m-1键值个数。

  1. 是一种多路平衡搜索树(并不是二叉的)。
  2. 根节点至少有两个子节点。
  3. 所有叶子节点在同一层,即所有叶子节点高度一致。
  4. 每个节点最多有m-1个关键字,根节点最少可以只有一个关键字,非根节点至少有m/2个关键字。
  5. 每个节点的关键字都按照从小到大的顺序排列,每个关键字的左子树中的所有关键字都小于它,而右子树中的关键字都大于它。
  6. 每个节点都存有索引和数据,也就是对应的key和value。

根节点关键字数量范围: 1<= k <=m-1

非根节点的关键字数量范围是:m/2 <= k <= m-1

   

    B数插入:

    插入的时候,需要记住:判断当前结点key的个数是否小于等于m-1,如果满足,直接插入即可,如果不满足,已结点的中间key将这个节点分为左右两个部分,中间的节点放到父节点即可。

    例如:在5阶B数中,节点最多有4个key,非根节点最少有2个key。

       插入18,70,50,40:

插入22:

插入22时,发现这个节点的关键字已经大于4了,所以需要进行分裂,分裂的规则在上面已经讲了,分裂之后,如下。

接着插入232539

分裂,得到下面的:

B树的删除操作:

https://www.cnblogs.com/nullzx/p/8729425.html

B树相比较于B+树的优点:

     B树的每一个节点都包含key和value,因此如果经常访问的元素离根节点更近,访问就更迅速。

B+树:

    B树里面所有节点都存储数据,这样导致在做范围查询的时候性能比较低。

    从B树结构图可以看出,每个节点不仅包含数据的key值,还有data值。而每一个页的存储空间是有限的,如果data数据较大时会导致每个节点(每一页)能存储的key的数量很小,当存储的数据量很大时会同样导致B树的深度较大,增大查询的磁盘I/O数量,进而影响查询效率。

    所以有B+树,例如InnoDB存储引擎就是用的B+树实现其索引结构。具体的原理是:在B+树中,所以数据记录节点都是按照键值大小顺序存放在叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+树的高度

   

   

和B树的相同点:

     1.根节点至少有一个元素。

     2.非根节点元素范围:m/2 <= k <= m-1。

和B树的不同点:

     1.B+树有两种类型节点:内部节点(也称索引节点)和叶子节点。内部节点就是非叶子节点,。内部节点不存储数据,只存储索引,数据都存储在叶子节点中。

      2. 内部节点中的key都按照从小到大的顺序排列,对于内部节点中的一个key,左数中的所有key都小于它,右树中的key都大于等于它。叶子节点中的记录也按照key的大小排列。

     3.每个叶子节点都存有相邻叶子节点的指针,叶子节点本身依靠关键字的大小从小到大排序。

     4. 父节点存有右孩子的第一个元素的索引。

B+树的优点:

      IO次数更少:B+树上不包含数据信息,因此在内存叶中能够存放更多的key。数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。

      遍历更加方便:B+树的叶子节点链式的,因此对整个叶子节点的遍历只需要一次线性遍历叶子节点即可。而且由于数据顺序排列并且相连,便于区间查询的搜索。而B树则需要每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中率没有B+树好。

为什么MySQL选择B+树做索引:

       B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。

       B+树的查询效率更加稳定:由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

       B+树更便于遍历:由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。

       B+树更适合基于范围的查询:B树在提高了IO性能的同时并没有解决元素遍历的我效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低。

InnoDB主键索引结构:

    聚簇索引是 MySQL 基于主键索引结构创建的,聚簇索引中数据页记录的是一条记录的完整的记录。

       从上面可以看出,MySQL的innoDB引擎中的B+树索引结构,包含有数据页和索引页。非叶子节点只包含索引页。

索引页

  • 记录的是每页数据页的页号和该数据页中最小的主键的记录,一张不够存就分裂到下一张,索引页太多会往上一层扩散
  • 索引页中的记录是通过单向链表连接的
  • 可以理解为,索引页其实维护了数据页,那么同时也有用于维护索引页的数据结构:其实也还叫索引页,只不过在不同的层级
  • 也就是说维护索引页的索引页是在真正存储记录和数据页的索引页的上一层

数据页

  • 数据页是其磁盘管理的最小单位
  • 数据在数据页中的存储是连续的,数据页中的数据是按照主键排序的(如果没有主键, 则会Unique key做主键,如果没有unique则由 MySQL自己维护的 ROW_ID 来排序的)
  • 数据页和数据页之间是通过双向链表来关联的,数据与数据之间是通过单向链表来关联的
  • 随着数据写入,就导致后一个数据页中的所有行并不一定比前一个数据页中的行的id大,此时触发页分裂的逻辑。页分裂的目的就是保证:后一个数据页中的所有行主键值比前一个数据页中主键值大。所以,一般不用UUID作为主键id,因为不是自增的,容易触发页分裂
  • InnoDB存储引擎中默认每个页的大小为16KB,可通过参数innodb_page_size将页的大小设置为4K、8K、16K。

       系统一个磁盘块的存储空间往往没有这么大,因此InnoDB每次申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小16KB。InnoDB在把磁盘数据读入到内存时会以页为基本单位,在查询数据时如果一个页中的每条数据都能有助于定位数据记录的位置,这将会减少磁盘I/O次数,提高查询效率,而B-Tree结构的数据可以让系统高效的找到数据所在的磁盘块。

通常一颗B+树能存放多少行数据?

       先假设B+树高度为2,那么这棵 B+ 树的存放总记录数为:根节点指针数*单个叶子节点记录行数。

       单个叶子节点(页)中的记录数=16K/1K=16。(这里假设一行记录的数据大小为 1K,实际上现在很多互联网业务数据记录大小通常就是 1K 左右,)。

那么现在我们需要计算出非叶子节点能存放多少指针?其实这也很好算,我们假设主键 ID 为 bigint 类型,长度为 8 字节,而指针大小在 InnoDB 源码中设置为 6 字节,这样一共 14 字节。我们一个页中能存放多少这样的单元,其实就代表有多少指针,即 16384/14=1170。

      那么可以算出一棵高度为 2 的 B+ 树,能存放 1170*16=18720 条这样的数据记录。根据同样的原理我们可以算出一个高度为 3 的 B+ 树可以存放:1170*1170*16=21902400 条这样的记录。

      所以在 InnoDB 中 B+ 树高度一般为 1-3 层,它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次 IO,所以通过主键索引查询通常只需要 1-3 次 IO 操作即可查找到数据。

聚簇索引和非聚簇索引:

聚集索引:

表数据按照索引的顺序来存储的,也就是说索引项的顺序与表中记录的物理顺序一致。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页。

在一张表上最多只能创建一个聚集索引,因为真实数据的物理顺序只能有一种。

从物理文件也可以看出 InnoDB(聚集索引)的数据文件只有数据结构文件.frm和数据文件.idb 其中.idb中存放的是数据和索引信息 是存放在一起的。

非聚集索引:

       表数据存储顺序与索引顺序无关。对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,其行数量与数据表行数据量一致。

       从物理文件中也可以看出 MyISAM(非聚集索引)的索引文件.MYI和数据文件.MYD是分开存储的 是相对独立的

聚簇索引和非聚簇索引的区别是:

       聚簇索引(innoDB)的叶子节点就是数据节点;

       而非聚簇索引(myisam)的叶子节点仍然是索引文件 只是这个索引文件中包含指向对应数据块的指针

      非聚簇索引,每次通过索引检索到所需行号(主键值)后,还需要通过叶子上的磁盘地址去磁盘内取数据(回行)消耗时间。为了优化这部分回行取数据时间,InnoDB 引擎采用了聚簇索引。

      聚簇索引,即将数据存入索引叶子页面上。对于 InnoDB 引擎来说,叶子页面不再存该行对应的地址,而是直接存储数据。

http://www.liuzk.com/410.html

      回表的含义:根据非主键索引查询到的结果并没有查找的字段值,此时就需要再次根据主键从聚簇索引的根节点开始查找,这样再次查找得到记录的过程叫回表。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值