【数据结构与算法】系列七 - 二叉树

……

一、树的基本概念

树(Tree)有节点、根节点、父节点、子节点、兄弟节点。

一棵树可以没有任何节点,称为空树

一棵树可以只有1个节点,也就是只有根节点。

每个节点下的树称为子树,二叉树有左子树和右子树。

如图:

  • 1是根节点
  • 2的父节点是1
  • 1的子节点是2、3、4、5、6
  • 21和22的父节点都是2,21和22是兄弟节点(22和31不是兄弟节点)

节点的度(degree:子树的个数(例:上图中节点2的度是2,节点3的度是1)。

树的度:所有节点度中的最大值(例:上图中子树最多的是根节点1的子节点,所以树的度是5)。

叶子节点(leaf:度为 0 的节点(例:上图中的4、21、221等节点)。

非叶子节点:度不为 0 的节点(例:上图中的22、5等节点)。

层数(level):根节点在第 1 层,根节点的子节点在第 2 层,以此类推(有些资料也从第 0 层开始计算)(例:上图中节点22的层数是3,节点5的层数是2)。

节点的深度(depth:从根节点到当前节点的唯一路径上的节点总数(例:上图中节点51的深度是3)。

节点的高度(height:从当前节点到最远叶子节点的路径上的节点总数(例:上图中节点2的高度是3)。

树的深度:所有节点深度中的最大值(例:上图中节点深度最大值是节点221,深度是4)。

树的高度:所有节点高度中的最大值(例:上图中节点高度最大值是节点1,高度是4)。

有序树:树中任意节点的子节点之间有顺序关系。

无序树:树中任意节点的子节点之间没有顺序关系,也称为“自由树”。

森林:由m(m ≥ 0)棵互不相交的树组成的集合。

树的深度等于树的高度。

二、二叉树

2.1. 二叉树的特点

  • 每个节点的度最大为 2(最多拥有 2 棵子树),最小为0
  • 左子树和右子树是有顺序的
  • 即使某节点只有一棵子树,也要区分左右子树

疑问:二叉树是有序树还是无序树?有序树。

2.2. 二叉树的性质

  1. 非空二叉树的第i层,最多有2^(i − 1)个节点( i ≥ 1 )。

  2. 在高度为h的二叉树上最多有2^h − 1个结点( h ≥ 1 )。

  3. 对于任何一棵非空二叉树,如果叶子节点个数为n0,度为 2 的节点个数为 n2,则有:n0 = n2 + 1

    • 假设度为 1 的节点个数为n1,那么二叉树的节点总数n = n0 + n1 + n2
    • 二叉树的边数T = n1 + 2 * n2,除了根节点的其他节点头部都有一条边,所以边数也可以是总节点数减去根节点,即T = n - 1。所以T = n1 + 2 * n2 = n0 + n1 + n2 – 1
    • 因此n0 = n2 + 1

2.3. 真二叉树(Proper Binary Tree

真二叉树:所有节点的都要么为 0,要么为 2。换句话:所有非叶子节点的度都为 2。

2.4. 满二叉树(Full Binary Tree

满二叉树:最后一层节点的度都为 0,其他节点的度都为 2。换句话:所有非叶子节点的度都为 2,且所有的叶子节点都在最后一层

  • 在同样高度的二叉树中,满二叉树的叶子节点数量最多、总节点数量最多。

  • 满二叉树一定是真二叉树,真二叉树不一定是满二叉树。

假设满二叉树的高度为h( h ≥ 1 ),那么:

  • 第 i 层的节点数量:2^(i − 1)
  • 叶子节点(第h层)数量:2^(h − 1)
  • 总节点数量:n = 2^h − 1 = 2^0 + 2^1 + 2^2 + ⋯ + 2^(h−1)
  • 高度:h = log2(n+1)

2.5. 完全二叉树(Complete Binary Tree

完全二叉树:对节点从上至下、左至右开始编号,其所有编号都能与相同高度的满二叉树中的编号对应。叶子节点只会出现最后 2 层,最后 1 层的叶子结点都靠左对齐。并且从根结点至倒数第 2 层是一棵满二叉树。

满二叉树:

完全二叉树:

满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树。

2.5.1. 完全二叉树的性质

  1. 度为 1 的节点只有左子树(因为左对齐)

  2. 度为 1 的节点要么是 1 个,要么是 0 个(因为从上至下,从左至右原则)

  3. 同样节点数量的二叉树,完全二叉树的高度最小(因为从上至下,从左至右原则)

  4. 假设完全二叉树的高度为h( h ≥ 1 ),那么:

    • 至少有2^0 + 2^1 + 2^2 + ⋯ + 2^(h−2) + 1 = 2^(h − 1)个节点
    • 最多有2^0 + 2^1 + 2^2 + ⋯ + 2^(h−1)= 2^h − 1个节点(满二叉树)
    • 总节点数量为n:
      • 2^(h − 1) ≤ n < 2^h
      • h − 1 ≤ log2n < h
      • h = floor(log2n) + 1
  5. 一棵有n个节点的完全二叉树(n > 0),从上到下、从左到右对节点从1 开始进行编号,对任意第i个节点:

    • 如果i = 1,它是根节点
    • 如果i > 1,它的父节点编号为floor(i / 2)
    • 如果2i ≤ n,它的左子节点编号为2i
    • 如果2i > n,它无左子节点
    • 如果2i + 1 ≤ n,它的右子节点编号为2i + 1
    • 如果2i + 1 > n,它无右子节点
  6. 一棵有n个节点的完全二叉树(n > 0),从上到下、从左到右对节点从0开始进行编号,对任意第i个节点:

    • 如果i = 0,它是根节点
    • 如果i > 0,它的父节点编号为floor((i – 1) / 2)
    • 如果2i + 1 ≤ n – 1,它的左子节点编号为2i + 1
    • 如果2i + 1 > n – 1,它无左子节点
    • 如果2i + 2 ≤ n – 1,它的右子节点编号为2i + 2
    • 如果2i + 2 > n – 1,它无右子节点

2.5.2. 完全二叉树的面试题

题目: 如果一棵完全二叉树有 768 个节点,求叶子节点的个数。

解答:

假设叶子节点个数为 n0,度为 1 的节点个数为 n1,度为 2 的节点个数为 n2。

  • 总结点个数n = n0 + n1 + n2
  • 由于n0 = n2 + 1,所以n = 2n0 + n1 – 1

由于完全二叉树的 n1 要么为 0,要么为 1。所以:

  • n1为1时,n = 2n0,n 必然是偶数
    • 叶子节点个数n0 = n / 2,非叶子节点个数n1 + n2 = n / 2
  • n1为0时,n = 2n0 – 1,n 必然是奇数
    • 叶子节点个数n0 = (n + 1) / 2,非叶子节点个数n1 + n2 = (n – 1) / 2

综上得出:

  • 叶子节点个数n0 = floor( (n + 1) / 2 ) = ceiling( n / 2 ),编程时由于n0和n是int类型,可以这样写:n0 = (n + 1) >> 1
  • 非叶子节点个数n1 + n2 = floor( n / 2 ) = ceiling( (n – 1) / 2 )
  • 因此叶子节点个数为 384