CSP-J 初赛(以满分为目标):第二十一课 《树与二叉树基础—— 一棵树,为什么会成为计算机最重要的数据结构之一?》


第二十一课:树与二叉树基础

------一棵树,为什么会成为计算机最重要的数据结构之一?

本课目标:

  1. 看懂树的基本结构;

  2. 掌握根、父亲、孩子、兄弟、叶子、度、层次、深度;

  3. 理解什么是二叉树;

  4. 分清"树"和"二叉树";

  5. 掌握满二叉树、完全二叉树;

  6. 会计算二叉树的层数、最多结点数;

  7. 为下一课"二叉树存储与遍历"打基础。


一、先从"家谱"理解什么是树

我们前面学习:

复制代码
数组
链表
栈
队列

这些数据结构都有一个共同特点:

数据之间大多是一条线。

例如链表:

复制代码
A → B → C → D → E

队列:

复制代码
A → B → C → D

可是现实世界中,有大量的数据不是"一条线"。

例如:

复制代码
                    校长
                  /      \
               教师       教师
              /   \        |
             学生 学生     学生

或者电脑文件夹:

复制代码
我的电脑
├── 学习
│   ├── C++
│   ├── 数学
│   └── 英语
├── 游戏
│   ├── 游戏A
│   └── 游戏B
└── 图片
    ├── 风景
    └── 家庭

这种:

一层一层向下分支

的结构,就是:

树(Tree)

讲义指出,树特别适合表示"元素之间具有分支层次关系的数据"。


二、为什么叫"树"?

现实中的树:

复制代码
        树干
         │
       ┌─┴─┐
       │   │
      树枝 树枝
      / \    \
     叶 叶    叶

数据结构里的树:

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

看起来是不是非常像?

所以计算机科学家就把这种结构叫:

Tree------树

不过要注意:

数据结构中的"树"通常画成根在上面、枝叶在下面。

和自然界的树倒过来。


三、树最重要的一个概念:结点

显然树并不是一根自然界的树。

C++中,它由一个一个:

结点(Node)

组成。

例如:

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

这里:

复制代码
A、B、C、D、E

都是结点。

我们对树结点的描述是:

一个结点包含一个数据元素,以及若干个指向其子树的分支。

所以大家可以简单理解成:

一个结点 + 它下面连接出去的若干个结点。


四、认识"根结点"

一棵树最上面的结点:

复制代码
        A
       / \
      B   C

A叫:

根结点(Root)

它有一个非常重要的特点:

根结点没有父亲。

就像家谱中的"祖先"。


五、认识父亲和孩子

看这棵树:

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

对于B来说:

复制代码
A是B的父结点

对于A来说:

复制代码
B、C是A的孩子

对于D来说:

复制代码
B是D的父结点

所以:

复制代码
A
↓
B
↓
D

可以理解成:

复制代码
爷爷
 ↓
爸爸
 ↓
孩子

我们分别定义了孩子结点和双亲结点。


六、兄弟是什么?

还是:

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

B和C:

复制代码
父亲都是A

所以:

B和C是兄弟。

D和E:

复制代码
父亲都是B

所以:

D和E也是兄弟。

具有同一父结点的子结点互称兄弟。


七、什么是叶子结点?

这是CSP-J特别喜欢考的概念。

看:

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

D没有孩子。

E没有孩子。

C也没有孩子。

所以:

复制代码
D、E、C

都是:

叶子结点

也叫:

终端结点

度为0的结点,就是叶子结点。

记住一句话:

下面没人了,就是叶子。


八、什么是分支结点?

反过来:

只要一个结点:

还有孩子

它就是:

分支结点

也叫:

非终端结点

例如:

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

A和B有孩子:

复制代码
A、B

所以:

复制代码
A、B = 分支结点
C、D、E = 叶子结点

我们就是按照"度大于0"为分支结点、"度为0"为叶子结点来定义的。


九、什么叫"结点的度"?

这是本课第一个重点。

一个结点的:

度 = 它有多少个孩子

例如:

复制代码
          A
       /  |  \
      B   C   D

A有:

复制代码
B、C、D

三个孩子。

所以:

复制代码
A的度 = 3

再看:

复制代码
       B
      / \
     E   F

B有两个孩子:

复制代码
B的度 = 2

而:

复制代码
C

没有孩子:

复制代码
C的度 = 0

我们给出的定义就是:

结点的度 = 一个结点拥有的子树数目。


十、树的度又是什么?

这里特别容易混。

假设:

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

各结点:

复制代码
A:3
B:2
C:0
D:0
E:0
F:0

那么:

复制代码
最大的度 = 3

因此:

这棵树的度 = 3

也就是说:

结点的度:看一个结点。
树的度:看整棵树,取最大值。

是这样定义的。


十一、一个容易错的题

如果:

复制代码
A有3个孩子
B有2个孩子
C有1个孩子
D没有孩子

问:

树的度是多少?

很多孩子会回答:

复制代码
3+2+1=6

这是错误的。

树的度是:

复制代码
max(3,2,1,0)
= 3

所以答案:

3


十二、什么是层次?

现在看:

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

我们的定义:

复制代码
根结点的层次 = 1

所以:

复制代码
A:第1层
B:第2层
C:第2层
D:第3层
E:第3层

本课定义:

结点的层次 = 从根结点到该结点所经过的路径长度 + 1。

所以采用的是:

根结点层次 = 1

这一点一定要特别提醒大家。

有时算法教材也可能定义:

复制代码
根的深度 = 0

而我们本课讨论树的层次时使用:

复制代码
根 = 第1层

初赛做题一定要以题目定义为准。


十三、什么是树的深度?

如果:

复制代码
A:第1层
B、C:第2层
D、E:第3层

那么最深的一层是:

复制代码
第3层

所以:

树的深度 = 3

树的深度为:

树中叶子结点具有的最大层次数。

简单记:

最深的叶子在哪一层,树的深度就是多少。


十四、路径是什么?

例如:

复制代码
       A
       |
       B
       |
       D

从A到D:

复制代码
A → B → D

这条路线就是:

路径

我们将路径定义为,从根到结点所经过的分支和结点构成的序列。

大家可以把它理解成:

从树根走到某个结点的路线。


十五、祖先和子孙

看:

复制代码
          A
         /
        B
       /
      D
     /
    G

对于G:

复制代码
A、B、D

都是G的:

祖先

而G是:

复制代码
A、B、D

的:

子孙


十六、到这里,我们把树的术语串起来

给大家画这样一张图:

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

请问:

A是什么?

复制代码
根结点

B、C、D是什么?

复制代码
A的孩子

B和C是什么关系?

复制代码
兄弟

E和F是什么关系?

复制代码
兄弟

B的父结点?

复制代码
A

E的父结点?

复制代码
B

E的度?

复制代码
0

B的度?

复制代码
2

A的度?

复制代码
3

整棵树的度?

复制代码
3

叶子?

复制代码
C、D、E、F

这就是我们要必须掌握的基本功。


十七、接下来进入本课重要的主角:二叉树

现在我们把刚才的树限制一下:

每个结点最多只能有两个孩子。

这时候就变成:

二叉树(Binary Tree)

例如:

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

每个结点:

复制代码
最多2个孩子

所以是二叉树。

二叉树的定义:

二叉树是由根结点以及左子树和右子树组成的有限集合;每个结点至多只有两棵子树。


十八、为什么叫"二叉"?

"二"很好理解:

复制代码
最多两个孩子

"叉"可以理解成:

复制代码
一个地方最多分成两条路

所以:

复制代码
       A
      / \
     B   C

就是:

复制代码
       A
      / \
    左   右

十九、二叉树最重要的特点:左右不能乱换

这是二叉树与普通树最容易混淆的地方。

看:

复制代码
        A
       / \
      B   C

在二叉树中:

复制代码
B = 左孩子
C = 右孩子

如果交换:

复制代码
        A
       / \
      C   B

这是:

另一棵二叉树

因为:

二叉树有左、右之分。

特别强调:

二叉树的子树有左右之分,其次序不能任意颠倒。


二十、普通树和二叉树有什么区别?

这是初赛选择题经常考的概念。

普通树

一个结点可以有:

复制代码
0个
1个
2个
3个
4个
......

孩子。

例如:

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

完全可以。


二叉树

一个结点最多:

复制代码
2个孩子

例如:

复制代码
       A
      / \
     B   C

但:

复制代码
       A
     / | \
    B  C  D

就不是二叉树。

总结:

普通树中结点最大度数没有限制,而二叉树结点最大度数为2;普通树没有左、右之分,而二叉树有左、右之分。


二十一、一个经典的思考题:3个结点有几种二叉树?

我们提出这个问题:

具有3个结点的二叉树可能有5种不同形态。

我们来数一数。


第一种

复制代码
    A
   /
  B
 /
C

第二种

复制代码
    A
   /
  B
   \
    C

第三种

复制代码
    A
     \
      B
     /
    C

第四种

复制代码
    A
     \
      B
       \
        C

第五种

复制代码
      A
     / \
    B   C

所以:

5种

为什么不是3种?

因为:

二叉树有"左"和"右"的区别。

这就是二叉树非常重要的特征。


二十二、什么是满二叉树?

接下来是初赛高频考点。

先画一棵:

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

你会发现:

复制代码
每一个非叶子结点
都有两个孩子

而且:

复制代码
每一层都排得满满的。

这就是:

满二叉树

定义是:

深度为 k 且有 2^k-1 个结点的二叉树。每一层的结点数都是该层的最大值。

这里采用讲义的层数定义:

复制代码
深度 = k

那么:

复制代码
第1层:1
第2层:2
第3层:4
第4层:8

总数:

复制代码
1 + 2 + 4 + 8 + ...

最终:

复制代码
2^k - 1

二十三、为什么是 2^k-1?

例如深度:

复制代码
k = 1

只有:

复制代码
1

而:

复制代码
2¹ - 1 = 1

正确。


深度:

复制代码
k = 2

有:

复制代码
1
2

一共:

复制代码
3

而:

复制代码
2² - 1 = 3

深度:

复制代码
k = 3

有:

复制代码
1
2
4

总共:

复制代码
7

而:

复制代码
2³ - 1 = 7

二十四、什么是完全二叉树?

完全二叉树非常重要。

例如:

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

它虽然不是满二叉树,因为:

复制代码
C只有左孩子

但是它仍然是:

完全二叉树

为什么?

因为:

上面的层都填满,最后一层从左向右连续排列,中间不能出现空洞。

完全二叉树的定义是:将完全二叉树与同深度的满二叉树编号1到n的结点逐一对应;

其特点是至多只有最下面两层的结点度可能小于2,而且倒数第二层如果只有一个孩子,必须是左孩子。


二十五、满二叉树和完全二叉树到底差在哪里?

这是初学者容易混淆的地方。

满二叉树

要求非常严格:

复制代码
每一层都满

例如:

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

完全二叉树

允许最后一层:

从右边开始缺一些。

例如:

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

可以。

但:

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

不可以。

因为最后一层出现了:

复制代码
D 空 F?

中间有空洞。


二十六、一个特别好用的判断方法

给孩子一句口诀:

完全二叉树:最后一层必须"左对齐"。

也就是说:

复制代码
√ √ √ √ 空 空

可以。

复制代码
√ √ √ 空 空 空

可以。

但:

复制代码
√ 空 √ √

不可以。

因为出现了:

"左边空了,右边还有人"。


二十七、满二叉树是完全二叉树吗?

答案:

当然是!

满二叉树是完全二叉树的一个特例。

所以关系是:

复制代码
        二叉树
           │
      ┌────┴────┐
      ↓         ↓
   完全二叉树   其他二叉树
      │
      ↓
   满二叉树

更准确地说:

复制代码
满二叉树 ⊂ 完全二叉树 ⊂ 二叉树

二十八、二叉树第i层最多有多少个结点?

二叉树的性质1。

如果根是第1层:

复制代码
第1层:1
第2层:2
第3层:4
第4层:8

所以:

第i层最多有 2^(i-1) 个结点

要掌握这一性质。


二十九、为什么是 2^(i-1)?

因为:

复制代码
第1层
1 = 2⁰

第2层
2 = 2¹

第3层
4 = 2²

第4层
8 = 2³

所以:

复制代码
第i层
= 2^(i-1)

三十、初赛题:第8层最多多少个结点?

直接套:

复制代码
2^(8-1)
= 2^7
= 128

答案:

128

这种题不要再画树了。

直接上公式。


三十一、深度为k的满二叉树有多少个结点?

刚才已经推出来:

复制代码
第1层:1
第2层:2
第3层:4
......
第k层:2^(k-1)

总数:

复制代码
1 + 2 + 4 + ... + 2^(k-1)

等比数列:

复制代码
= 2^k - 1

所以:

满二叉树结点数 = 2^k-1


三十二、完全二叉树有多少个结点?

如果深度为:

复制代码
k

那么:

最少

前面层数尽量少,只有最后一层一个结点:

复制代码
1
2
4
...
2^(k-2)
1

讲义给出的结论是:

深度为 k 的完全二叉树,至少有 2^(k-1) 个结点,最多有 2^k-1 个结点。

所以:

复制代码
最少:2^(k-1)
最多:2^k - 1

三十三、举个例子

如果:

复制代码
k = 4

完全二叉树最少:

复制代码
2^(4-1)
= 8

最多:

复制代码
2^4 - 1
= 15

所以:

复制代码
8 ≤ n ≤ 15

三十四、一道经典的选择题

题目:

一棵完全二叉树有1001个结点,问叶子结点个数。

这里实际上可以利用一个重要规律:

对于一棵二叉树,如果:

复制代码
n0 = 度为0的结点数
n1 = 度为1的结点数
n2 = 度为2的结点数

则:

复制代码
n0 = n2 + 1

这个结论我们可以放到下一阶段继续重点推导。

对于完全二叉树,还可以利用:

编号从1开始时,编号大于 n/2 的结点都是叶子。

这个结论后面讲二叉树顺序存储时会重点解释。


三十五、对于我们小学生,先建立:

复制代码
形状 → 规律 → 公式

而不是:

复制代码
公式 → 死记

比如:

复制代码
        ●
       / \
      ●   ●
     / \ / \
    ●  ●●  ●

先看到:

复制代码
1
2
4

再想到:

复制代码
2^(i-1)

然后自然得到:

复制代码
1+2+4+...=2^k-1

这样孩子以后遇到陌生题也不会慌。


方法一:利用完全二叉树的编号

完全二叉树从上到下、从左到右编号:

复制代码
              1
           /     \
          2       3
        /  \     /  \
       4    5   6    7
      ...

对于有 n 个结点的完全二叉树:

编号大于 ⌊n/2⌋ \lfloor 的结点全部是叶子结点。

这里:

n=1001

所以:

⌊1001/2⌋=500

因此:

复制代码
1 ~ 500       非叶子结点
501 ~ 1001    叶子结点

叶子数量:

1001−500=501

正确答案是:

501 个


方法二:从"最后一层"理解

1001 个结点的完全二叉树:

前面的 500 个结点可以看成:

复制代码
1 ~ 500

它们负责产生孩子。

从:

复制代码
501 ~ 1001

开始的结点没有孩子,因此全部是叶子。

数量:

1001−500=501

所以答案是:

501


记忆口诀:

完全二叉树,从 n/2 + 1开始,全是叶子。


三十六、CSP-J最喜欢考的"概念陷阱"

陷阱1:树的度

错误:

复制代码
所有结点度数加起来

正确:

复制代码
最大结点度数

陷阱2:叶子结点

错误:

复制代码
最下面一层所有结点

正确:

复制代码
度为0的结点

陷阱3:二叉树必须有两个孩子

错误。

二叉树是:

复制代码
最多两个

可以:

复制代码
0个
1个
2个

陷阱4:完全二叉树必须每个结点都有两个孩子

错误。

例如:

复制代码
        A
       / \
      B   C
     /
    D

完全二叉树可以存在一个孩子。


陷阱5:满二叉树和完全二叉树一样

错误。

关系:

复制代码
满二叉树
   ↓
一定是
   ↓
完全二叉树

但反过来:

复制代码
完全二叉树
   ↓
不一定
   ↓
满二叉树

三十七、课堂小测①

给出:

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

问:

1. A的度?

复制代码
3

2. B的度?

复制代码
2

3. C的度?

复制代码
0

4. 这棵树的度?

复制代码
3

5. 叶子有哪些?

复制代码
C、D、E、F

6. B和C是什么关系?

复制代码
兄弟

三十八、课堂小测②:判断是不是二叉树

A

复制代码
      A
     / \
    B   C

是。

B

复制代码
      A
     /|\
    B C D

不是二叉树。

因为:

复制代码
A有3个孩子。

三十九、课堂小测③:判断是不是完全二叉树

图1

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

答案:


图2

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

答案:

不是

因为最后一层不满足从左向右连续排列。


四十、课堂小测④:计算

一棵二叉树第5层最多有多少个结点?

复制代码
2^(5-1)
= 16

答案:

16


四十一、课堂小测⑤:满二叉树

一棵深度为5的满二叉树有多少个结点?

复制代码
2^5 - 1
= 31

答案:

31


四十二、把本课知识画成一张地图

复制代码
                         树
                         │
              ┌──────────┴──────────┐
              ↓                     ↓
          普通树                  二叉树
        孩子数不限              最多2个孩子
                                      │
                              ┌───────┴───────┐
                              ↓               ↓
                         完全二叉树          其他
                              │
                              ↓
                          满二叉树

树的基本术语:

复制代码
根
│
├── 父结点
├── 孩子
├── 兄弟
├── 祖先
├── 子孙
├── 叶子:度=0
├── 分支结点:度>0
├── 结点的度:孩子数量
└── 树的度:所有结点度的最大值

二叉树:

复制代码
第i层最多:
2^(i-1)

深度k的满二叉树:
2^k - 1

深度k的完全二叉树:
2^(k-1) ≤ n ≤ 2^k - 1

四十三、本课要让同学们掌握的5个概念

① 什么是树?

树是一种具有层次和分支关系的数据结构。

② 什么是二叉树?

每个结点最多有两个孩子,而且有左、右之分。

③ 什么是叶子?

没有孩子的结点,度为0。

④ 什么是完全二叉树?

除了最后一层外,上面各层都是满的,最后一层从左向右连续排列。

⑤ 满二叉树和完全二叉树什么关系?

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


四十四、本课与CSP-J初赛的连接

这一课虽然看起来"只是概念",实际上是后面大量初赛题目的基础。

在树和二叉树习题中,有大量:

  • 树的度;

  • 结点的度;

  • 叶子结点;

  • 完全二叉树叶子数;

  • 二叉树某一层最多结点数;

  • 二叉树最少结点数;

  • 前序、中序、后序遍历;

  • 完全二叉树高度;

  • 二叉树顺序存储编号。

例如直接考查"第 i 层最多有多少结点"、完全二叉树结点数量,以及根据遍历序列还原二叉树。

所以我们要把"树的语言"学会。否则到了后面看到:

复制代码
tree[x].left
tree[x].right

或者:

复制代码
dfs(root)

大家会觉得每一个词都很陌生。


四十五、本课作业

画5棵不同的树,每棵树同学们都要回答:

复制代码
① 根结点是谁?
② 有多少个结点?
③ 哪些是叶子?
④ 哪些是分支结点?
⑤ 某结点的度是多少?
⑥ 整棵树的度是多少?
⑦ 某结点在哪一层?
⑧ 树的深度是多少?
⑨ 是不是二叉树?
⑩ 是不是完全二叉树?
⑪ 是不是满二叉树?

尤其最后的三问一定要反复练。


相关推荐
别动我齐刘海38 分钟前
从0到1独立搭建机器人软件系统
c++·人工智能·神经网络·opencv·目标检测·机器学习·机器人
dear_bi_MyOnly42 分钟前
数组字符串深度解析:从入门到卡牌实战
开发语言·c++·学习
小欣加油1 小时前
Leetcode2058 找出临界点之间的最小和最大距离
数据结构·c++·算法·leetcode·职场和发展
王老师青少年编程2 小时前
2026年山东省小学组【信息学体验营】复赛真题及题解T2:小兔子爬楼梯
c++·真题·山东省·csp·信奥赛·复赛·信息学体验营
Yfhonier2 小时前
6441. 特别的除法
c++·算法
OPEN-F2 小时前
C++17新特性精讲:结构化绑定、if constexpr与实用类型
开发语言·c++
OPEN-F2 小时前
C++并发编程:线程与互斥锁
开发语言·c++
码匠许师傅2 小时前
【设计模式精讲】11.桥接模式(Bridge)
c++·设计模式·桥接模式·uml
小小、码农2 小时前
【网络】套接字(Socket)编程——TCP版
linux·服务器·网络·c++·网络协议·tcp/ip