数据结构——二叉树汇总


1. 二叉树

1.1 满二叉树

  一个高度为 h h h,并含有 2 k − 1 2^k-1 2k1个结点的二叉树为满二叉树。即树中每一层都含有最多的结点。如图(a)所示,其中叶子结点都在树的最下面一层,并且除了叶子结点以外,其他结点的度均为2。
在这里插入图片描述

1.2 完全二叉树

  设一个高度为 h h h,并含有 n n n个结点的二叉树,当且仅当其每一个结点都与高度为 h h h的满二叉树中编号 1 ∼ n 1\sim n 1n一一对应时,称为完全二叉树,如图(b)所示。这种树的特点如下:

  1. i ≤ ⌊ n / 2 ⌋ i\leq \lfloor n/2 \rfloor in/2,则结点i为分支结点,否则为叶结点。
  2. 叶子结点只可能在层次最大的两层上出现。对于最大层次中的儿子结点,都依次排序在该层最左边的位置上。
  3. 如果有度为1的结点,只可能有一个,且该结点只有左孩子而无右孩子。
  4. 按层序编号后,一旦出现某结点(其编号为 i i i)为叶子结点或只有左孩子,则编号大于 i i i的结点均为叶子结点。
  5. n n n为技术,则每个分支结点都有左子女和右子女;若&n&为偶数,则编号最大的分支结点(编号为 n / 2 n/2 n/2)只有左子女,没有右子女,其余分支结点左、右子女都有。

1.3 二叉树性质

  1. 非空二叉树上叶子结点数等于度为2的结点数加1,即 N 0 = N 2 + 1 N_0=N_2+1 N0=N2+1
  2. 非空二叉树上第K层最多有 2 K − 1 2^{K-1} 2K1个结点( K ≥ 1 K\geq1 K1,跟为第一层,往下依次加1);
  3. 高度为H的二叉树至多有个 2 H − 1 2^{H-1} 2H1结点( H ≥ 1 H\geq1 H1);
  4. 对完全二叉树按照从上到下、从左到右的顺序依次编号 1 , 2 , 3 , . . . , N 1,2,3,...,N 1,2,3,...,N,则有以下关系:
    • i > 1 i>1 i>1时,结点 i i i的双亲结点的编号为 ⌊ i / 2 ⌋ \lfloor i/2 \rfloor i/2。即当 i i i为偶数时,其双亲结点的编号为 i / 2 i/2 i/2,它是双亲结点的左孩子;即当 i i i为奇数时,其双亲结点的编号为 ( i − 1 ) / 2 (i-1)/2 (i1)/2,它是双亲结点的右孩子;
    • 2 i ≤ N 2i\leq N 2iN时,结点 i i i的左孩子结点编号为 2 i 2i 2i,否则无左孩子;
    • 2 i + 1 ≤ N 2i+1\leq N 2i+1N时,结点 i i i的右孩子结点编号为 2 i + 1 2i+1 2i+1,否则无右孩子;
    • 结点 i i i所在的层次(深度)为 ⌊ l o g 2 i ⌋ + 1 \lfloor log_2i\rfloor+1 log2i+1
  5. 具有 N N N ( N > 0 ) (N>0) (N>0)结点的完全二叉树的高度为 ⌈ l o g 2 ( N + 1 ) ⌉ + 1 \lceil log_2(N+1)\rceil+1 log2(N+1)+1 ⌊ l o g 2 N ⌋ + 1 \lfloor log_2N\rfloor+1 log2N+1

2. 二叉树应用

2.1 二叉排序树

  二叉排序树,也称为二叉查找树,二叉搜索树,或BST(Binary Search Tree)。二叉排序树或者是一棵空树,或者是一棵具有下列特性的非空二叉树:

  • 若左子树非空,则左子树上所有的结点关键字值均小于根结点的关键字值;
  • 若右子树非空,则右子树上所有的结点关键字值均大于根结点的关键字值;
  • 左、右子树本身也是一棵二叉排序树。

2.2 平衡二叉树

  在构建二叉排序树的时候,可能会出现这么种极端情况,如下图所示。

在这种情况下,虽然也满足二叉排序树的标准,但是有条“大长腿”看起来比较畸形。在这种情况下,就有了平衡二叉树。

  对于二叉树而言,如果满足任意结点的左、右子树高度差的绝对值不超过1,则其就是一棵平衡二叉树,简称平衡树(VAL树)。定义结点左子树和右子树的高度差为该结点的平衡因子,则平衡二叉树任意结点的平衡因子的值只可能是-1、1和0。

2.3 红黑树

  有了上面的铺垫,下面来讲解一个比较难懂,但是却非常重要,面试经常会被问到的东西——红黑树。它是自平衡的二叉查找树,在进行插入和删除等可能会破坏树的平衡的操作时,需要重新自处理达到平衡状态

  红黑树(Red-Black Tree, RBT)是一个自平衡(不是绝对的平衡)的二叉查找树(BST),树上的每个结点都遵循下面的规则:

  • 每个结点不是黑色便是红色;
  • 根结点是黑色;
  • 没有两个相邻的红色结点(红色结点不能有红色父结点或红色子结点,并没有说不能出现连续的黑色结点);
  • 任一结点(包括根)到NULL(树尾端,叶子结点下方挂的两个空节点,并且认为他们是黑色的)的任何路径,所含的黑结点数相同。

2.3.1 旋转(rotation)

  在讲解插入结点之前,先来了解下红黑树的旋转操作,主要有左旋和右旋两种情况,分别如下:

  • 左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。下图中将红色结点左旋,注意蓝色结点的位置变换。
    在这里插入图片描述
  • 右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。下图中将红色结点左旋,注意蓝色结点的位置变换。
    在这里插入图片描述

  其实这个旋转很简单,可以把这些树想做一串葡萄。拎起来需要旋转的那个结点,这个时候手提着的这个葡萄可能有三个分支,把中间的那个分支摘下来,如果是左旋的话,就将它挂在手提葡萄左侧的那个葡萄上;如果是右旋的话,就将它挂在手提葡萄右侧的那个葡萄上。完事儿~~

  此外还有一个概念比较重要,就是染色(recolor)。也就是说黑色的结点可以变成红色,红色的结点也可以变黑。

2.3.2 插入结点

  结点的插入是一个比较麻烦的操作,为啥说比较麻烦嘞,因为后面还有个更麻烦的操作——删除。不过大家不要怕,仔细研究研究,掌握了技巧就不难了。

  结点插入可以分为多种情况,在插入节点之前,这里先把红黑树满足的规则再强调一遍:

  • 条件1:每个结点不是黑色便是红色;
  • 条件2:根结点是黑色;
  • 条件3:没有两个相邻的红色结点(红色结点不能有红色父结点或红色子结点,并没有说不能出现连续的黑色结点);
  • 条件4:任一结点(包括根)到NULL(树尾端,叶子结点下方挂的两个空节点,并且认为他们是黑色的)的任何路径,所含的黑结点数相同。
2.3.2.1 插入结点x时,如果树中没有结点(空树)

  插入结点x时,如果树中没有结点(空树)时,该结点x作为树的根(root)。根据条件2,该结点是黑色。后续情况均默认新插入的结点x为红色。

2.3.2.2 如果结点x不是根结点,且其父节点为黑结点

  如果结点x不是根结点,且其父节点为黑结点。由于插入的结点是红色的,并不会影响红黑树的平衡,因此直接插入即可,无需做自平衡(即不需要调整)。

2.3.2.3 如果结点x不是根结点,且其父结点为红结点

  这个时候就不能直接插入,否则与条件3冲突,即结点x即其父节点均为红色。因此,需要对其进行分情况讨论。

2.3.2.3.1 当结点x的叔叔结点为红色时
  • 则将P(父结点)和U(叔叔结点)设置为黑色

  • 将PP(祖父节点)设置为红色

  • 把PP设置为当前插入结点
    在这里插入图片描述

      一般情况下操作如情景1所示,在插入结点x时,如果结点x的父节点(P)和叔叔结点(U)均为红色,则将P和U修改成为黑色,并将祖父节点(PP)修改成红色。此时修改PP的时候,其实也相当于插入了新节点,需要再对PP的父节点进行判断,并根据结点插入规则向上依次修改,直至最终红黑树自平衡。

      再来看下特殊情况,如情景2所示,此时PP刚好为根结点时,那么根据条件2,我们必须把PP重新设为黑色,那么树的红黑结构变为:黑黑红。换句话说,从根结点到叶子结点的路径中,黑色结点增加了。这也是唯一一种会增加红黑树黑色结点层数的插入情景。
      同理,插入结点x的父节点P在祖父节点PP的左子树,跟插入结点x的父节点P在祖父节点PP的右子树操作方式一样。

2.3.2.3.2 当结点x的叔叔结点为黑色或不存在,并且插入结点的父亲结点是祖父结点的左子结点
2.3.2.3.2.1 插入结点是其父结点的左子结点
  • 将P设为黑色
  • 将PP设为红色
  • 对PP进行右旋
    在这里插入图片描述当然,此时也可以将结点x和结点PP设置成黑色,将结点P设置成红色,但是这时由于插入了红色结点,需要从结点P开始再次向上调整,增加了不必要的麻烦,因此不建议。
2.3.2.3.2.2 插入结点是其父结点的右子结点
  • 对P进行左旋
  • 将PP设为红色
  • 对PP进行左旋
    在这里插入图片描述
2.3.2.3.3 当结点x叔叔结点不存在或为黑结点,并且插入结点的父亲结点是祖父结点的右子结点

  这种情况和2.3.2.3.3节“当结点x的叔叔结点为黑色或不存在,并且插入结点的父亲结点是祖父结点的左子结点”刚好相反,操作也刚好相反。

2.3.2.3.3.1 插入结点是其父结点的右子结点

在这里插入图片描述

2.3.2.3.3.1 插入结点是其父结点的左子结点

在这里插入图片描述这就是插入操作的全部了。

2.3.3 删除结点

2.4 红黑树应用

map, set, multimap, and multiset
上述四种容器采用红黑树实现,红黑树是平衡二叉树的一种。不同操作的时间复杂度近似为:

  • 插入: O(logN)
  • 查看:O(logN)
  • 删除:O(logN)

hash_map, hash_set, hash_multimap, and hash_multiset
上述四种容器采用哈希表实现,不同操作的时间复杂度为:

  • 插入:O(1),最坏情况O(N)。
  • 查看:O(1),最坏情况O(N)。
  • 删除:O(1),最坏情况O(N)。

记住,如果你采用合适的哈希函数,你可能永远不会看到最坏情况。但是记住这一点是有必要的。

3. B+树

3.1 B+树与B树的区别

  • 每个节点上的指针上限为2d而不是2d+1(d为节点的出度) ;
  • 有k个子结点的结点必然有k个关键码;
  • 非叶结点仅具有索引作用,数据信息则存放在叶结点中;
  • 树的所有叶结点构成一个有序链表,可以按照关键码排序的次序遍历全部记录;
  • 而B+树中间节点没有Data数据,所以同样大小的磁盘页可以容纳更多的节点元素。所以数据量相同的情况下,B+树比B树更加“矮胖“,因此使用的IO查询次数更少。
  • 由于B树的查找并不稳定(最好的情况是查询根节点,最坏查询叶子节点)。而B树每一次查找都是稳定的。
  • 比起B树,B+树 ①IO次数更少 ②查询性能很稳定 ③范围查询更简便

在这里插入图片描述
  如上图所示,蓝色结点中存储的是索引,并没有存储数据。红色结点中存储数据,并没有存储索引。非叶子结点中存储的是子结点中数据最大值的索引。

3.2 B+树查找

假设现在需要查找上图中的15(任意数据都需要相同的查询次数),则:

  • 第一步
    搜索根结点,根据索引数据选择查询根结点的右子树。
    在这里插入图片描述
  • 第二步:
    根据根右子树中的索引信息,选择查询该结点的右子树。
    在这里插入图片描述
  • 第三步:
    在对应叶子结点中查找数,并将查找结果返回。
    在这里插入图片描述

3.3 B+树插入、删除

B树和B+树的操作详解

参考文献

  1. a
  2. b
  3. B+树总结
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值