红黑树,B树,二叉树之间的不同

二叉树

二叉树是一种树状结构,每个节点最多只有两个子节点:左子节点和右子节点。

结构

cpp 复制代码
        A
       / \
      B   C
     / \   \
    D   E   F

这里:

  • A是根节点
  • B和C是A的子节点
  • D和E是B的子节点
  • F是C的子节点

基本术语

  • 节点(Node):树的每个元素,比如A、B、C
  • 根节点(Root):树的最顶端节点,比如以上示例的A
  • 叶子节点(Leaf):没有子节点的节点(D、E、F)
  • 子节点(Child):某节点的直接下级节点(B是A的子节点,D是B的子节点)
  • 父节点(Parent):某节点的上级节点(D的父节点是B,B的父节点是A)
  • 深度(Depth):节点到根的距离(层数)
  • 高度(Height):节点到叶子节点的最长路径
深度(Depth) 高度(Height)
定义 节点到的距离(层数) 节点到叶子的最长路径(层数)
例子 根深度为0,叶子深度为最大 叶子高度为0,树根高度最大,反映从节点到叶子路径

深度和高度不同,不要搞错了。

类型

类型 描述 举例
普通二叉树 任意节点最多两个子节点 上面示意的树
满二叉树 所有叶子节点都在同一层,且每个非叶子节点有两个子节点 每层的节点数都满
完全二叉树 除最后一层外,每层节点都满,最后一层节点尽可能集中在左侧 完全二叉堆
平衡二叉树 任意节点左右子树高度差不超过1 AVL树、红黑树

遍历方式

  • 前序遍历(Pre-order): 根 -> 左子树 -> 右子树
  • 中序遍历(In-order): 左子树 -> 根 -> 右子树
  • 后序遍历(Post-order): 左子树 -> 右子树 -> 根
  • 层序遍历(Level-order): 按层从上到下、从左到右

示例:

假设树如下:

cpp 复制代码
        A
       / \
      B   C
     / \   \
    D   E   F
  • 前序:A -> B -> D -> E -> C -> F
  • 中序:D -> B -> E -> A -> C -> F
  • 后序:D -> E -> B -> F -> C -> A
  • 层序:A, B, C, D, E, F

性质

  • 节点数关系:

    在一棵二叉树中,节点总数为:

    复制代码
                          ∇=叶子节点数+非叶子节点数
  • 深度与高度:

    • 树的深度(层数)越多,树越高
    • 平衡的二叉树操作通常为了减少树的高度,以优化性能

二叉搜索树

对于树中的每个节点:

  • 左子树上所有节点的值都小于这个节点的值
  • 右子树上所有节点的值都大于这个节点的值
    这样,整棵树就按照"二叉搜索树的性质"排序了。

实例

假设插入数字:10, 5, 15, 3, 7

结构大致是:

cpp 复制代码
        10
       /   \
      5     15
     / \
    3   7
  • 每个节点左边都比它小,右边都比它大
  • 可以快速实现搜索、插入、删除

作用

  • 快速查找:通过中序遍历,得到一个有序序列
  • 基础结构:很多复杂的树(如AVL、红黑树)都是在BST基础上改进的
  • 应用广泛:数据库索引、字典等

平衡二叉树

平衡二叉树是一类特殊的二叉搜索树,其任何节点的左右子树的高度差(平衡因子)都不超过1。这样保证树的高度始终保持在 logn 的级别。

使用平衡二叉树的原因

  • 普通BST在极端情况下可能退化成链表:

    • 比如按顺序插入有序数据,会形成一条长链,查找变为线性时间 O(n)。
  • 平衡树维持树的高度最小化,保证查找、插入、删除操作高效。

常见的平衡二叉树

  • AVL树(Adelson-Velsky and Landis Tree)

    • 平衡因子(Balance factor):每个节点左子树高度减右子树高度,要求为-1、0、1。
    • 每次插入或删除后,可能需要"旋转"操作来修复平衡。
  • 红黑树

    • 性质:每个节点是红或黑,满足特定规则,使树始终大致平衡。
    • 特点:插入、删除后通过"变色"和"旋转"保持平衡,常用于Java的TreeMap、C++的map。

实例

以AVL树为例:如何保持平衡

  • 插入/删除节点后:

    • 从插入位置向上回溯,检测每个节点的平衡因子
    • 如果某个节点的平衡因子超出范围(>1 或 <-1),就需要"旋转"调整
  • 旋转类型:

  • 左旋(Single Left Rotation)

  • 右旋(Single Right Rotation)

  • 左右旋(Left-Right Rotation)

  • 右左旋(Right-Left Rotation)

这些旋转操作帮助重新平衡树,保持每个节点的平衡因子在允许范围内。

旋转

单旋转
  • LL旋转(左左不平衡 -> 右旋)

场景:

插入新节点后,左子树的左子节点变得过高,导致树左侧"倾斜"。

cpp 复制代码
    不平衡前                     旋转后
        A                            B
       /                            / \
      B        ------ 右旋 ------          C   A
     /                                
    C                                
  • 将A进行右旋转 将节点B作为新的根节点,A成为B的右子节点,C(原B的左子节点)作为A的左子节点。
  • RR旋转(右右不平衡 -> 左旋)

场景:

插入新节点后,右子树的右子节点变得过高。

cpp 复制代码
  不平衡前                     旋转后
      A                             B
       \                         /   \
        B        ------ 右旋 ------      A     C
           \                           \
            C                           D
  • 将A左旋转 成为左节点
双旋转
  • LR旋转(左-右不平衡)

场景:

左子树的右子树高,需先左旋左子树,再右旋根节点。

cpp 复制代码
不平衡前                         旋转后
       A                              
      /                             
     B        ------ 先左旋 B 在右旋A ------   B   
      \                            /  \ 
       C                          C    A

总结

特点 说明
每个节点的平衡因子(左右子树高度差) ≤ 1 \leq 1 ≤1(即-1, 0, 1)
保持树的高度在 log ⁡ n \log n logn 级别 确保操作时间为 O(\\log n)
通过旋转调整平衡 在插入、删除操作后自动修复

旋转子树时其他不变,当子树旋转结束后,谁是子树根节点,全树的根节点就连接谁。

红黑树

红黑树是一类自平衡的二叉搜索树,它通过"颜色标记"以及一系列规则,确保树的高度大致平衡,从而在插入、删除和查找操作中实现 O(logn) 的时间复杂度。

节点属性

每个节点有:

  • 一个值(数据)
  • 一个颜色(红或黑)
    • 在红黑树的定义中,黑色节点的数量(黑高)决定了路径的长度,而红色节点只是"装饰"
    • 红节点不增加黑色节点的数量,只是"点缀",用于调节树结构。
    • 黑节点:像"楼层数",决定了路径的基本高度。
    • 红节点:像"楼层之间的装饰",不会加高,但帮助控制设计。
  • 指向左右子节点的指针
  • 指向父节点的指针(有的实现会有)

结构

cpp 复制代码
        (8B)
       /     \
    (4R)     (12R)
    /  \      /   \
 (2B) (6B) (10B) (14B)
  • R代表红色,B代表黑色

关键属性

  • 节点是红色或黑色
  • 根节点是黑色
    • 保持树的"起点"黑色,有助于维护路径上黑色节点的平衡。
    • 这样可以避免频繁出现连续的红色起点,也简化性质的维护。
  • 所有叶子(NIL节点,即空子节点)都是黑色
    • 方便统一处理空子节点,简化算法设计。
    • 通过将叶子定义为黑色,确保路径中的黑色节点计数一致。
  • 红色节点的子节点必须是黑色(不能连续两个红节点)
    • 连续的红色节点会导致路径中的黑色节点数变少,从而使树高度偏高,平衡性差
  • 从任何节点到叶子节点的所有路径都包含相同数目的黑色节点(黑色平衡)

作用与优势

  • 保持树的平衡:通过颜色规则避免树变得太高(退化为链表)。
  • 保证操作效率:插入、删除、查找都在 O(logn) 范围内。

插入操作

插入新节点类似BST:

  • 新节点总是插入为红色(为了不是破坏黑色平衡)
  • 然后修复颜色和旋转,保持红黑性质

插入修复(修复红色连续性)

可能出现:

  • 红节点的父节点也是红色(违反性质 4)

修复方法:

  • 情况1:叔叔节点为红色
cpp 复制代码
       A
      /  \
     B    C
    / \
   D   E
  • D的父节点是 B。

  • B的兄弟节点(父节点的兄弟)就是 C。

    • 将父节点和叔叔节点变为黑色
    • 将祖父节点变为红色
    • 继续向上修正
  • 情况2:叔叔节点为黑色或不存在(空节点)

    • 进行左旋或右旋调整,以恢复性质,往往以"旋转+颜色调整"完成
状况 处理方法
父节点是红色,叔叔节点是红色 变色 + 重新向上修复
父节点是红色,叔叔节点是黑色(或不存在) 旋转 + 变色(形成左右旋转的调整)

例:

插入节点7

  • 作为红色节点插入
  • 如果父节点是黑色,无需调整
  • 如果父节点是红色(出现连续红色),进行旋转和颜色调整

删除操作

  • 类似BST,但需要调整来恢复红黑性质
  • 可能涉及"向下传递"的颜色和旋转调整

核心思想

  • 红黑树通过限制"连续红节点"和"黑色路径长度一致",保证树的高度在"对数级"
  • 调整主要依靠颜色变换和旋转

总结

特性 描述
节点颜色 每个节点是红或黑
根节点 必须是黑色
叶子节点(NIL) 全部是黑色,作为叶节点,用来简化算法
红色节点的子节点 必须是黑色(不能连续两个红色节点)
所有路径的黑色节点数相同 从根到任意叶子路径,黑色节点数一致(黑高平衡)

如果出现连续红节点会出现的问题:

  • 形成连续的红色链(如:连续三个红色节点),
  • 破坏黑色节点平衡的性质(因为黑色节点数变少了),
  • 使得树的高度可能增长,变得不平衡。

红黑树的设计宗旨是限制红色链的长度:

  • 规则"红色节点的子节点必须是黑色",实际上限制了连续红色的长度最多为1。
  • 这样,路径上的红色节点最多只有一层,避免了"红色链"无限长,从而保证树的平衡。

B树

  • B树是一棵阶数为 m 的多路平衡搜索树。
  • 每个节点最多有 m 个子节点(即 m-1 个关键字)。

基本性质

  • 每个内部节点(非叶子节点):
    • 含有 k (m/2 - 1 ≤ k ≤ m-1) 个关键字
    • 有 k+1 个子节点
  • 所有叶子节点在同一层(树的高度平衡)。
  • 每个节点(除了根节点),关键字数都在允许范围内。
    根节点:
    • 可以只有1个关键字(或更少,视具体定义而定),但一般至少有一个关键字,除非树为空。

具体阶数

  • 阶(阶数)为 m
  • 每个节点(除了叶子)至少有 ⌊m/2⌋ 个关键字(除了根)
  • 每个节点最多有 m-1 个关键字

结构特点

特性 描述
多路 每个内部节点可以有多个子节点(非二叉树)。
平衡 所有叶子节点在同一层,保证查找、插入、删除的平均和最坏时间都 O(log n)。
关键字存储 节点内存放有序的关键字,用于导航搜索。
节省空间 由于多个关键字在一节点,减少树的高度,从而减少磁盘操作。

操作

  • 1. 查找
    • 从根节点开始,比较目标值与当前节点的关键字。
    • 根据比较结果,沿对应子节点递归查找。
    • 直到找到目标或到达叶子。
  • 2. 插入
    • 先找到插入位置(类似查找),在叶子节点插入。
    • 如果叶子已满(达到最大关键字数),则分裂:
      • 将中间关键字上升到父节点
      • 分裂成两个节点
    • 如果父节点也满,则递归向上分裂。
  • 3. 删除
    • 找到目标关键字所在节点:
      • 如果是叶子,直接删除。
      • 如果是内部节点,用前驱或后继节点替换,然后再删除叶子中的值。
    • 如果删除后节点关键字数少于最小(合规性),需要借兄弟节点或合并节点。

与B+树的区别

  • B树:所有节点(内部和叶子)都存关键字。
  • B+树:只有叶子存关键字,内部节点存索引,支持更高的查询效率。

实例

假设 m=4(阶为4):

  • 每个节点最多有 3 个关键字和 4 个子节点。
  • 每个非根节点至少有 2 个关键字(即⌊4/2⌋)。

简单的B树结构:

cpp 复制代码
        [10, 20]
       /    |    \
  [5, 7]  [12, 15] [22, 25]
节点类型 关键字 子节点说明 叶子或非叶子
根节点 [10, 20] 3个子节点: - 小于10 - 10到20之间 - 大于20 非叶子
左子节点 [5, 7] 无子节点(叶子) (如果它是叶子) 叶子
中左子节点 [12, 15] 无子节点(叶子) 叶子
右子节点 [22, 25] 无子节点(叶子) 叶子
  • 如果这是一个完整的B树,这些叶子可以在同一层,存放实际数据(例如:具体的元素值)。
  • 叶子节点中的关键字存放实际数据,或者指向存放数据的存储位置。
节点类型 存放内容 作用
内部节点(非叶子) 索引/导航用的关键字 引导搜索,决定下一步到哪个子节点
叶子节点 存放实际数据或数据指针 具体的数据存储点;支持范围查询和顺序扫描
  • 内部节点:
    • 10, 20\],用来引导:\<10,10到20,\>20

    • 5, 7\],\[12, 15\] ,\[22, 25\],存放实际数据元素。

相关推荐
肥猪猪爸20 分钟前
使用LSTM进行时间序列分析
数据结构·人工智能·rnn·深度学习·算法·lstm·时间序列分析
哈听星1 小时前
数值积分实验
算法
2401_837088501 小时前
List<Integer> list=new ArrayList<>()
数据结构·list
<但凡.2 小时前
C++修炼:map和set的封装
数据结构·c++
生活很暖很治愈2 小时前
《函数栈帧的创建和销毁》
c语言·数据结构·c++·编辑器
yours_Gabriel2 小时前
【力扣】面试题 01.04. 回文排列
java·数据结构·leetcode
Musennn2 小时前
leetcode106.从中序与后序遍历序列构造二叉树:索引定位与递归分治的完美配合
java·数据结构·算法·leetcode
OKkankan3 小时前
类和对象(中1)
c语言·数据结构·c++·算法
共享家95273 小时前
算法刷题记录:滑动窗口经典题目解析
c++·算法·leetcode
啥都想学的又啥都不会的研究生4 小时前
常规算法学习
java·数据结构·b树·学习·算法·排序算法