完全二叉树
完全二叉树
基本概念
完全二叉树:基于二叉树,要求除了最下层外,其余各层都是满节点。并且,最后一层的节点必须尽可能向左放。
例:下面所有二叉树都不是完全二叉树:
特征
- 叶子节点之可能在最下面的两层出现
- 对任意结点,若其
右分支下的子孙最大层次为L
,则其左分支下的子孙的最大层次必为L或L+1
。 - 所有节点中,最多只有一个节点度为1(只有一个孩子)。
实现
方便起见,完全二叉树一般用数组实现而不用链表。
对于用数组存储的完全二叉树,有以下特点:(下标从0开始)(根节点层数为1)
- 如果一个节点在数组中下标为
i
,则它在树中的层数为 \(\left\lfloor log_2{(i+1)} \right\rfloor\) (向下取整),它的左子节点在数组中对应的下标为:\(2i+1\)(如果存在),右子节点在数组中对应的下标为\(2i+2\)(如果存在)。 - 如果完全二叉树总共有
n (n>0)
个节点,那么树高: \(h=\left \lfloor log_2{n} \right \rfloor+1\) (或者\(\left\lceil log_2{(n+1)} \right\rceil\))。 - 如果完全二叉树树高
h
,那么这个完全二叉树最多拥有\(2^h-1\)个节点。
如果根节点下标从1开始,那么第一条中,左子节点对应下标改为:\(2i\),右子节点对应下标改为:\(2i+1\)。(相比于下标从0开始,直接-1)
用数组构建完全二叉树
给定一个数组,用层序便利构建二叉树。然后输出它的中序遍历。
例如:
C++实现:
1 |
|
非递归方法构建完全二叉树的思路:
使用队列保存已经构建好的部分的层序遍历顺序。
- 首先,构建根节点,然后根节点进入队列。
- 循环:
- 如果队列不为空,从队列中取出节点元素。
- 构建该节点的左右子节点(如果存在的话)。并且将构建好的左子节点和右子节点分别入队。也就是将下一层的元素放入队列。
- 如果队列为空,跳出循环。
递归方法构建思路:
- 传入节点数组。并且传入当前要构建的节点在数组中的下标。
- 根据数组中的元素值构建当前节点。
- 判断左右子节点:(假设完全二叉树根节点对应数组下标为1)
- 左子节点(
2i+1
)存在:递归调用函数进行构建 - 右子节点(
2i+2
)存在:递归调用函数进行构建
- 左子节点(
- 返回当前构建好的节点的指针,便于将不同节点连接在一起。
完全N叉树
与完全二叉树类似:
- 除了最后一层,其余各层已经满节点。
- 最后一层的所有节点尽可能向左边放。
由后续遍历构建完全N叉树
给定一个大小为M的数组arr[]
,其中包含完整 N 叉树的后序遍历,任务是生成 N 叉树并打印其前序遍历。
例图:
C++实现:
1 |
|
正确输出:
1 | 1 2 5 6 7 3 8 9 4 |
由后续遍历构建完全N叉树的思路
核心思路:递归。难点:如何求得根节点的各个子节点所在子树的节点总数。
- 传入要构建的树的后续遍历,以及总节点数。还有树的分叉数:N。
- 识别根节点。同时求得树高(推导数学公式)
- 循环:
- 计算根节点的第
i
个孩子所在的子树所拥有的节点数(数学方法+逻辑推理)(\(1\leq i\leq k\))(此处为了便于理解引入变量i
,实际实现时循环中并不存在变量i
) - 构建根节点的第
i
个孩子所在的子树(递归。传入后续遍历(通过原数组偏移量和节点数))。构建完成后挂载到根节点上。 - 记录已经构建完成的子树的节点数之和(循环累加)
- 如果:已经构建完成的节点树之和等于总节点数-1,(如果构建成功只能是等于,不能是大于),那么该树构建完成。
- 计算根节点的第
- 返回构建的根节点。
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.