判断题:树中除根节点外,每个节点都有且仅有一个父节点。
考点:树的概念(A1)。
解析:树是 个节点的有限集合:根节点唯一且无父节点,其余每个节点有且仅有一个父节点。✅ 正确
排除法:无(判断题)。混淆点:树不能有环、不能有多根;节点的"度"是它的孩子个数。
关联 · 二叉树定义(A2):二叉树是每个节点最多两个孩子且左右有序的树。
判断题:二叉树中每个节点最多有两个子节点,且左右子树有顺序之分。
考点:二叉树定义(A2)。
解析:二叉树每个节点最多两个子节点(可为 0/1/2 个),且左右子树有顺序(左右孩子互换是两棵不同的二叉树)。✅ 正确
排除法:无(判断题)。混淆点:普通树的"孩子"无左右之分——二叉树与普通树的关键区别就在"左右有序"。
关联 · 树的概念(A1):二叉树是树的特例(度数 ≤ 2 且有序)。
二叉树第 层(根为第 层)最多有( )个节点。
考点:第 i 层节点数(A3)。
解析:第 层最多 个:第 4 层 = 。✅ B
排除法:A 是层数;C 是第 5 层;D 是三层满树总数。
关联 · 深度与节点数(A5):第 1~k 层求和 = 。
验算: ✓
判断题: 个节点的树(二叉树)恰有 条边。
考点:节点与边(A4)。
解析:树中除根外每个节点恰有一条"连向父节点"的边—— 个节点 = 条边。✅ 正确
排除法:无(判断题)。混淆点:有 条边的连通图必有环——树是"无环连通"的最小边集。
关联 · 树的概念(A1): 条边是"树"的判定条件之一。
深度为 (根深度为 )的二叉树最多有( )个节点。
考点:深度与节点数(A5)。
解析:深度 的二叉树最多 个节点(每层全满):。✅ B
排除法:A 是第 5 层的节点数;C 忘了减 1;D 是深度 4。
关联 · 满二叉树节点数(B3): 恰是满二叉树的节点数公式。
验算: ✓
判断题:任意二叉树中,叶子节点数 = 度为 2 的节点数 + 1。
考点:叶子与度2(A6)。
解析:任意二叉树:(叶子数 = 度为 2 的节点数 + 1)——由 与 (边数)联立得出。✅ 正确
排除法:无(判断题)。混淆点:与 (度为 1 的节点)无关——度为 1 的节点再多也不影响公式。
关联 · 应用(D1):已知叶子数直接求 ,反之亦然。
判断题:满二叉树每一层的节点数都达到最大值。
考点:满二叉树(B1)。
解析:满二叉树每一层的节点数都达到最大值(第 层 个),所有叶子在同一层。✅ 正确
排除法:无(判断题)。混淆点:完全二叉树允许最后一层不满(B2)——"满"比"完全"更严格。
关联 · 满 vs 完全(B6):满 ⊆ 完全——满必完全、完全不必满。
判断题:完全二叉树除最后一层外每层都满,且最后一层节点靠左排列。
考点:完全二叉树(B2)。
解析:完全二叉树:除最后一层外每层全满,最后一层节点从左到右连续排列。✅ 正确
排除法:无(判断题)。混淆点:最后一层"靠左连续"是关键——右侧缺、左侧不空。
关联 · 顺序存储(D4):完全二叉树的"连续编号"特性让它适合数组存储。
深度为 的满二叉树共有( )个节点。
考点:满二叉树节点数(B3)。
解析:深度 的满二叉树 = 个节点:深度 4 = 。✅ C
排除法:A 是深度 3;B 是最后一层节点数;D 是 (没减 1)。
关联 · 深度与节点数(A5):满二叉树正是"最多节点数"的实现。
验算: ✓
有 个节点的完全二叉树的深度是( )(根深度为 )。
考点:完全二叉树深度(B4)。
解析: 个节点的完全二叉树深度 = :,深度 = 。✅ B
排除法:A 是 (忘了 +1);C 是 层的量级误判;D 无来源。
关联 · 高度范围(D3):深度为 的二叉树最少 个(一条链)、最多 个。
验算: ✓
完全二叉树数组存储(根编号为 ),编号为 的节点的左孩子编号是( )。
考点:孩子编号(B5)。
解析:完全二叉树数组存储(根编号 1):节点 的左孩子 = 、右孩子 = 。✅ A
排除法:B 是右孩子;C 是父节点;D 无意义。
关联 · 编号规则(H3):父亲 = ——"左 2i、右 2i+1、父 i/2"一套公式。
判断题:满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树。
考点:满与完全(B6)。
解析:满二叉树满足完全二叉树的全部条件(每层全满、最后一层连续)——满必完全;完全二叉树的最后一层可以不齐——完全不必满。✅ 正确
排除法:无(判断题)。混淆点:反过来"完全必满"是错的(深度 3、5 个节点的完全二叉树就不是满的)。
关联 · 满/完全定义(B1/B2):记住包含关系"满 ⊆ 完全"。
前序遍历的顺序是( )。
考点:前序遍历(C1)。
解析:前序 = 根 → 左 → 右:先访问根节点,再递归遍历左子树、右子树。✅ A
排除法:B 是中序;C 是后序;D 是层序。
关联 · 三序对比(H1):前序"根最先"、中序"根在中间"、后序"根最后"——看"根"的位置记三序。
中序遍历的顺序是( )。
考点:中序遍历(C2)。
解析:中序 = 左 → 根 → 右:先递归遍历左子树,再访问根,最后右子树。✅ B
排除法:A 前序;C 后序;D 层序。
关联 · BST 中序有序(F4):中序对 BST 输出升序——中序遍历最重要的应用。
后序遍历的顺序是( )。
考点:后序遍历(C3)。
解析:后序 = 左 → 右 → 根:左右子树都访问完才访问根。✅ C
排除法:A 前序;B 中序;D 层序。
关联 · 表达式树(C7):后序遍历 = 后缀表达式——先算子再算根运算符。
判断题:层序遍历从上到下、从左到右逐层访问,通常用队列实现。
考点:层序遍历(C4)。
解析:层序 = 从上到下逐层、每层从左到右——用队列实现:出队访问、左右孩子入队。✅ 正确
排除法:无(判断题)。混淆点:用栈实现层序就变成深度优先(P3 的坑)——层序必须队列。
关联 · 层序代码(J5):队列 + 判孩子非空入队——BFS 在树上的应用。
某二叉树前序 A B C、中序 B A C,则该树的后序是( )。
考点:遍历序列还原(C5)。
解析:前序 A B C 定根 A,中序 B A C 分左右:B 左、C 右。树:A(左 B, 右 C),后序 = 左-右-根 = B C A。✅ A
排除法:B C B A 是右左根(把 C 放左);C/D 顺序错。
关联 · 前序中序定树(C6):前序定根 + 中序分左右 = 唯一确定——还原树的两步法。
验算:后序 = 左(B) 右(C) 根(A) = B C A ✓
判断题:已知前序遍历和中序遍历序列,可以唯一确定一棵二叉树。
考点:前序中序定树(C6)。
解析:前序第一个是根,中序中根的位置把序列分成左右子树——递归下去唯一确定。✅ 正确
排除法:无(判断题)。混淆点:只有前序(或只有后序)不能唯一确定;前序+后序也不行——必须含中序。
关联 · 重建代码(O2):前序+中序重建是真题高频——"前序取根、中序分边"。
判断题:表达式树的前序遍历 = 前缀表达式、中序遍历 = 中缀表达式、后序遍历 = 后缀表达式。
考点:表达式树(C7)。
解析:表达式树的三种遍历对应三种记法:前序 = 前缀(+ab)、中序 = 中缀(a+b)、后序 = 后缀(ab+)。✅ 正确
排除法:无(判断题)。混淆点:中缀输出可能需要加括号(中序遍历本身不加括号会丢优先级)。
关联 · 后缀表达式(第 8 章 G2):后序遍历表达式树 = 后缀表达式——两者一一对应。
某二叉树有 个叶子节点,则度为 的节点有( )个。
考点:叶子与度2应用(D1)。
解析::7 个叶子 → 度为 2 的节点 = 个。✅ C
排除法:A 忘了减 1;B 加了 1;D 无来源。
关联 · 公式(A6):——正向反向都要会代。
验算: ✓
个节点的完全二叉树有( )个叶子节点。
考点:完全二叉树叶子数(D2)。
解析:7 个节点的完全二叉树 = 深度 3 的满树(),最后一层 4 个叶子。✅ B
排除法:A 是第 2 层节点数;C/D 无来源。
关联 · 满二叉树(B3):7 恰是满树——叶子全在最后一层( 个)。
判断题:深度为 的二叉树节点数范围是 。
考点:高度与节点范围(D3)。
解析:深度 的二叉树节点数:最少 个(每层一个、成一条链)、最多 个(满二叉树)。✅ 正确
排除法:无(判断题)。混淆点:范围两端对应"最瘦的链"和"最胖的满树"。
关联 · 完全二叉树深度(B4): 个节点的完全二叉树深度是 ——范围公式的具体化。
判断题:完全二叉树适合用数组顺序存储(按层编号),一般二叉树用数组会浪费空间。
考点:顺序存储(D4)。
解析:完全二叉树编号连续(/),数组存储零浪费;一般二叉树按满树编号,缺的节点留空位——浪费空间。✅ 正确
排除法:无(判断题)。混淆点:顺序存储适合"完全",链式存储适合"一般"——按树形选存储。
关联 · 孩子编号(B5):编号规则是顺序存储的寻址方式。
判断题:树(二叉树)的高度 = 根节点到最远叶子的边数(或层数)。
考点:树的高度(D5)。
解析:树的高度 = 根到最远叶子的层数(或边数,两种定义,看题目口径)——高度 即深度 。✅ 正确
排除法:无(判断题)。混淆点:空树高度记 0(递归定义,见 G2);单节点树高度 1。
关联 · 递归求深度(G2):高度 = max(左高, 右高) + 1——递归定义与概念一致。
判断题:二叉链表存储二叉树,每个节点含数据域、左孩子指针、右孩子指针。
考点:二叉链表(D6)。
解析:二叉链表节点 = 数据域 + 左孩子指针 + 右孩子指针; 个节点有 个指针域、其中 个为空。✅ 正确
排除法:无(判断题)。混淆点:空指针数 = (由 条边可知非空指针 个,共 个域)——线索二叉树就是利用这些空指针。
关联 · 节点结构(I1):
struct Node { int data; Node *l, *r; }——二叉链表的 C++ 实现。
判断题:哈夫曼树是带权路径长度(WPL)最小的二叉树。
考点:哈夫曼树(E1)。
解析:哈夫曼树 = 带权路径长度(WPL)最小的二叉树——权值大的节点离根近。✅ 正确
排除法:无(判断题)。混淆点:哈夫曼树不一定是完全二叉树、不唯一(合并顺序可不同),但 WPL 最小。
关联 · WPL(E2):WPL = Σ 权值 × 路径长度——哈夫曼树让 WPL 最小。
权值为 的哈夫曼树的 WPL 是( )。
考点:WPL 计算(E2)。
解析:{2,3,4,5} 的哈夫曼树:合并 2+3=5 → {4,5,5};4+5=9 → {5,9};5+9=14。树形:2、3 在深度 3,4 在深度 2,5 在深度 1。WPL = 。✅ C
排除法:A 是根权值(和);B 是 乘错;D 是等长编码 2 位 × 20。
关联 · 哈夫曼构造(E5):每次合并最小的两个——贪心构造。
验算: ✓
判断题:哈夫曼编码把出现频率高的字符编成较短的码字。
考点:哈夫曼编码(E3)。
解析:哈夫曼编码按频率分配码长:频率高 → 码字短——总编码长度最短。✅ 正确
排除法:无(判断题)。混淆点:频率低的字符码字反而长——"短码给高频"是压缩的核心。
关联 · 前缀码(E4):哈夫曼码是前缀码——长短不一也不会有歧义。
判断题:哈夫曼编码是前缀编码——任何一个码字都不是另一个码字的前缀,解码无歧义。
考点:前缀码(E4)。
解析:前缀码:任何码字都不是另一个码字的前缀——解码从左到右扫,遇到完整码字立即译出,无歧义。✅ 正确
排除法:无(判断题)。混淆点:如 0 和 01 冲突(0 是 01 的前缀)——解码 01 不知道是 0+1 还是 01。
关联 · 哈夫曼编码(E3):哈夫曼码字全在叶子上 → 天然前缀码。
判断题:构造哈夫曼树时,每次从集合中取出权值最小的两个节点合并成新节点(贪心)。
考点:构造贪心(E5)。
解析:哈夫曼构造:反复取权值最小的两个节点合并成新节点(权值 = 两者之和)放回集合,直到只剩一个根——贪心策略。✅ 正确
排除法:无(判断题)。混淆点:每次必须取最小两个(可相等取任意)——"最小两合并"是哈夫曼的核心动作。
关联 · 建树模拟(O3):用排序维护最小值是常见实现。
判断题:哈夫曼编码的总长度 = 各字符权值 × 其码字长度的和 = WPL。
考点:编码长度(E6)。
解析:总编码长度 = Σ(字符权值 × 码字长度) = WPL——哈夫曼树的 WPL 就是编码总长度。✅ 正确
排除法:无(判断题)。混淆点:权值 = 出现频率(次数),不是字符值。
关联 · WPL(E2):WPL 的另一个身份 = 压缩后的总码长。
判断题:频率分布不均时,哈夫曼编码总长度通常短于等长编码。
考点:哈夫曼 vs 等长(E7)。
解析:频率分布不均时,哈夫曼给高频短码——总长度短于等长编码;频率完全均匀时两者相当。✅ 正确
排除法:无(判断题)。混淆点:哈夫曼编码不总是更短(均匀分布时等长码已最优)——"通常"两字是严谨的。
关联 · 前缀码(E4):等长码也是前缀码;哈夫曼的优越性来自"按频率分配长度"。
判断题:二叉搜索树(BST)中,左子树所有节点值 < 根 < 右子树所有节点值(假设无重复)。
考点:BST 定义(F1)。
解析:二叉搜索树:任一节点左子树所有值 < 该节点 < 右子树所有值(无重复假设下)——递归成立。✅ 正确
排除法:无(判断题)。混淆点:只是"左孩子小、右孩子大"不够——必须整棵子树都满足(L6 判 BST 的考点)。
关联 · BST 查找(F2):左小右大的结构让查找每次排除一半。
判断题:BST 查找从根开始,目标比当前节点小走左子树、大走右子树——每次排除一半。
考点:BST 查找路径(F2)。
解析:从根开始:目标 < 当前 → 走左;目标 > 当前 → 走右;相等 → 命中——每步排除一棵子树。✅ 正确
排除法:无(判断题)。混淆点:平均 、最坏 (树退化成链)——复杂度与树形相关。
关联 · BST 查找代码(L1):
x < p->data ? 找左 : 找右——代码就是定义的直译。
判断题:BST 插入新值也是"比当前小走左、大走右",最终落在空位成为叶子。
考点:BST 插入(F3)。
解析:插入与查找同路:小走左、大走右,直到空位——新节点总是叶子。✅ 正确
排除法:无(判断题)。混淆点:BST 插入不改已有结构——"插在空位"是它与平衡树的最大区别。
关联 · BST 插入代码(L2):
Node* &p引用参数让空位赋值回传——实现细节。
判断题:对 BST 做中序遍历,得到的序列是有序的(升序)。
考点:BST 中序有序(F4)。
解析:中序 = 左-根-右,BST 左 < 根 < 右——递归展开就是升序序列。✅ 正确
排除法:无(判断题)。混淆点:BST 中序升序 ⇔ BST 有序性的等价判定(L6 用它判 BST)。
关联 · BST 中序代码(L3):中序遍历 BST = 排序输出——"BST + 中序 = 排序"。
判断题:完全二叉树可以用数组表示:根存下标 1,节点 的左孩子是 、右孩子是 ——恰好按层序依次连续存放。
考点:完全二叉树的数组表示(F5)。
解析:根在下标 1,节点 的左孩子 、右孩子 ,按层序连续存放——完全二叉树数组表示的三个公式。✅ 正确
排除法:无(判断题)。混淆点:下标从 0 起时公式变为左孩子 、右孩子 (两套约定别混用)。
关联 · 完全二叉树的数组表示法(B 组):概念题与本题呼应。
单选题:完全二叉树数组表示(根在下标 1)中,下标 的节点的父节点下标是?
考点:完全二叉树的下标关系(F6)。
解析:父 = 子 ÷ 2(下标 1 起):。正确答案 A。
排除法:B()是 ;C/D 是 的孩子下标(、),方向记反。
关联 · 完全二叉树的数组表示(F5):父子公式是数组表示的根基。
判断题:完全二叉树按层序存放在数组中时,数组的先后顺序恰好就是层序遍历的结果。
考点:完全二叉树的层序与下标(F7)。
解析:按层序存放 → 数组顺序 = 层序遍历结果——这也是"数组表示"之所以叫"层序存储"的原因。✅ 正确
排除法:无(判断题)。混淆点:层序 = 从上到下、每层从左到右,与数组下标 1, 2, 3, … 完全一致。
关联 · 层序遍历(C 组):层序 = BFS 遍历(第 16 章队列)。
判断题:二叉树可以递归定义:空树是二叉树,或"根 + 左子树(二叉树)+ 右子树(二叉树)"。
考点:递归定义(G1)。
解析:二叉树递归定义:空树是二叉树;或根节点 + 左子树(二叉树)+ 右子树(二叉树)。✅ 正确
排除法:无(判断题)。混淆点:递归定义是二叉树一切递归算法的依据——遍历/求深度/求节点数都是它的直译。
关联 · 递归求深度(G2):
max(左,右)+1就是递归定义的直接翻译。
判断题:二叉树深度 = max(左子树深度, 右子树深度) + 1,空树深度为 0。
考点:递归求深度(G2)。
解析:深度 = 左右子树深度的最大值 + 1(自己这一层);空树深度 0。✅ 正确
排除法:无(判断题)。混淆点:用"和"(左+右+1)是求节点数——深度用 max、节点数用加法。
关联 · 求节点数(G3):两个公式对比:深度 = max+1、节点数 = 和+1。
判断题:二叉树节点数 = 左子树节点数 + 右子树节点数 + 1,空树为 0。
考点:递归求节点数(G3)。
解析:节点数 = 左子树节点数 + 右子树节点数 + 1(根自己);空树 0。✅ 正确
排除法:无(判断题)。混淆点:与深度公式(max+1)对比记忆——一个是"多少层"、一个是"多少个"。
关联 · 求叶子数(G4):节点数/叶子数/深度是递归三件套。
判断题:叶子节点数 = 左子树叶子数 + 右子树叶子数;单节点树叶子数为 1。
考点:递归求叶子数(G4)。
解析:叶子(左右皆空)返回 1;否则 = 左子树叶子 + 右子树叶子;空树 0。✅ 正确
排除法:无(判断题)。混淆点:叶子判定 = l == NULL && r == NULL——"两个都空"才叫叶子。
关联 · 求节点数(G3):叶子数只是多一个"是否叶子"的判断分支。
判断题:BST 查找的平均复杂度为 ,最坏(退化成链)为 。
考点:BST 查找复杂度(G5)。
解析:平衡的 BST 每次排除一半——平均 ;退化成链(插入有序数据)时 = 线性表,最坏 。✅ 正确
排除法:无(判断题)。混淆点: 是"平均/平衡"前提——BST 不保证平衡(平衡树如 AVL 才保证)。
关联 · BST 查找(F2):复杂度取决于树形——"插入顺序"决定树形。
判断题:BST 插入的平均复杂度 ,插入后中序仍有序。
考点:BST 插入复杂度(G6)。
解析:插入沿查找路径走到底( 平均),新节点落成叶子——插入后中序仍有序。✅ 正确
排除法:无(判断题)。混淆点:插入不动已有节点——BST 没有"旋转"(那是平衡树的操作)。
关联 · BST 插入(F3):查找路径 = 插入路径——两个操作同一路线。
判断题:后序遍历 = 左子树 → 右子树 → 根节点,根节点最后访问。
考点:遍历别记混(H1)。
解析:后序 = 左 → 右 → 根:根最后访问。✅ 正确
排除法:无(判断题)。混淆点:前序"根最先"、中序"根在中间"、后序"根最后"——用"根的位置"记三序最稳。
关联 · 三序遍历(C1/C2/C3):前 ABC 根、中 BAC 根、后 BCA 根。
判断题:完全二叉树要求最后一层靠左连续,满二叉树要求所有层全满。
考点:完全 vs 满(H2)。
解析:完全 = 最后一层可不满但靠左连续;满 = 所有层全满——满更严格。✅ 正确
排除法:无(判断题)。混淆点:"完全"的重点是"连续"、"满"的重点是"全满"。
关联 · 满 vs 完全(B6):满 ⊆ 完全。
判断题:完全二叉树数组存储时根节点编号为 ,孩子 、、父亲 。
考点:编号从 1 开始(H3)。
解析:完全二叉树数组存储根编号 1:左孩子 、右孩子 、父亲 。✅ 正确
排除法:无(判断题)。混淆点:编号从 1 起(不是 0)——从 0 起则左孩子 、右孩子 ,两套公式别混。
关联 · 孩子编号(B5):1 起编号是 CSP 惯例,读题看清下标起点。
判断题:WPL = 每个叶子节点的权值 × 根到它的路径长度之和(不是节点值相加)。
考点:WPL 陷阱(H4)。
解析:WPL = Σ(叶子权值 × 根到叶子的路径长度)——是"权值乘路径",不是简单相加。✅ 正确
排除法:无(判断题)。混淆点:把 WPL 算成权值和(14)或全乘 1——路径长度漏算是最高频错误(见 E2)。
关联 · WPL(E2):手算 WPL:画出哈夫曼树,逐叶"权值 × 深度"相加。
下列说法错误的是( )。
考点:综合判断(H5)。
解析:D 错误——前序 = 根 → 左 → 右(根最先);"左→右→根"是后序。✅ D
排除法:A 满必完全(B6)✓;B 哈夫曼是前缀码(E4)✓;C BST 中序有序(F4)✓。
关联 · 本章串联:A(B6)、B(E4)、C(F4)、D(C1)——综合题 = 细节判断的集合。
01struct Node { 02 int data; // 数据域 03 Node *lchild; // 左孩子指针 04 Node *rchild; // 右孩子指针 05};
判断题:二叉链表每个节点含数据域和左右孩子两个指针,空孩子指针为 NULL。
考点:二叉链表结构(I1)。
实现要点:二叉链表 = 结构体里三个成员:数据 + 左孩子指针 + 右孩子指针——每个节点存"自己 + 两个入口",整棵树靠指针串起来;空孩子存 NULL,叶子节点的两个指针都是 NULL。
解析:Node{data, lchild, rchild} 是二叉链表的节点;空孩子指针为 NULL。✅ 正确
排除法:无(判断题)。混淆点:不是三叉链表(那还带父指针)——二叉链表是标准存储。
关联 · 二叉链表(D6): 节点 个指针域、 个空——线索二叉树利用这些空指针。
01const int MAXN = 100; 02int tree[MAXN]; // 完全二叉树的顺序存储:根下标 1,左孩子 2i、右孩子 2i+1 03// 空位存 -1 表示没有节点
判断题:一般二叉树(非完全)顺序存储时中间会有大量空洞,浪费空间。
考点:顺序存储(I2)。
实现要点:顺序存储 = 把完全二叉树按层序编号塞进数组(根 1、左 、右 );一般二叉树也按满树编号,缺的节点留空位——树越"斜"浪费越大。
解析:非完全二叉树顺序存储会产生空洞。✅ 正确
排除法:无(判断题)。混淆点:完全二叉树顺序存储零浪费——选择存储方式看树形。
关联 · 顺序存储(D4):完全 → 数组、一般 → 链表——按需选存储。
01const int MAXN = 100; 02int tree[MAXN]; 03int n; 04// 按层序读入 n 个节点的完全二叉树(1 号下标开始存,空节点读入 -1)
判断题:读入顺序 = 层序遍历顺序,tree[i] 的孩子在 tree[2*i]、tree[2*i+1]。
考点:读入建树(I3)。
实现要点:按层序读入完全二叉树 = 下标即层序位置:第 1 个数是根、之后逐层从左到右;空节点读入 -1 占位,保证后续节点编号不乱。
解析:读入顺序 = 层序,tree[i] 的孩子在 、。✅ 正确
排除法:无(判断题)。混淆点:空节点必须占位(-1),否则孩子编号错位——顺序存储的空位不可省。
关联 · 孩子编号(B5):读入 + 编号规则 = 数组树——两件事合起来就能建树。
// 完全二叉树数组存储,根编号 1,编号 i 的节点: // 左孩子 = 2 * i,右孩子 = 2 * i + 1,父亲 = i / 2
编号为 的节点的父节点编号是( )。
考点:孩子编号(I4)。
实现要点:数组树寻址三公式:左孩子 、右孩子 、父亲 ——乘 2 向下、除 2 向上。
解析:编号 6 的父亲 = 。✅ B
排除法:A 是左孩子方向记反;C 是左孩子;D 无来源。
关联 · 编号从 1 开始(H3):根从 1 起是这套公式的前提。
验算: ✓
01const int MAXN = 100; 02int tree[MAXN]; // tree[1]=10, tree[2]=20, tree[3]=30, 03 // tree[4]=40, tree[5]=50, tree[6]=60, tree[7]=70 04 05// 前序遍历(递归版): 06void pre(int i) { 07 if (i > 7 || tree[i] == -1) return; 08 cout << tree[i] << ' '; 09 pre(2 * i); 10 pre(2 * i + 1); 11}
调用 pre(1) 输出为( )。
考点:数组树前序输出(I5)。
实现要点:数组树的前序 = 递归:先输出自己,再 pre(2i) 左子树、pre(2i+1) 右子树——数组下标就是指针,递归结构不变。
解析:树(下标 1 起:10,20,30,40,50,60,70):前序 = 根左右 = 10 20 40 50 30 60 70。✅ A
排除法:B 是中序;C 是层序;D 是后序。
关联 · 前序(C1):数组版与指针版同一递归——"先自己、再左、再右"。
验算:10 → 20 → 40 → 50 → 30 → 60 → 70 ✓
01// 满二叉树:深度 k,节点总数 = 2^k - 1 02int cnt(int k) { 03 return (1 << k) - 1; 04}
判断题:深度 的满二叉树调用 cnt(4) 返回 。
考点:满二叉树节点数(I6)。
实现要点:满树节点数 = ——代码里 (1 << k) - 1 就是"1 左移 k 位减 1"( 的位运算写法)。
解析:深度 4 满树 = 。✅ 正确
排除法:无(判断题)。混淆点:1 << k 是 ——左移 1 位 = 乘 2。
关联 · 满二叉树节点数(B3): 公式的代码化。
验算: ✓
01struct Node { char data; Node *l, *r; }; 02// 树形: A 03// / \ 04// B C 05// / \ / 06// D E F 07void pre(Node *p) { 08 if (p == NULL) return; 09 cout << p->data; 10 pre(p->l); 11 pre(p->r); 12}
前序遍历输出为( )。
考点:前序遍历输出(J1)。
实现要点:前序递归三步:判空返回 → 输出根 → 递归左 → 递归右——"根左右"三个字直译成三行代码;判空是出口(P1 的坑)。
解析:树 A(B(D,E), C(F)):A → B → D → E → C → F = ABDECF。✅ A
排除法:B DBEAFC 是中序;C DEBFCA 是后序;D ABCDEF 是层序。
关联 · 前序(C1):代码顺序 = 定义顺序——"根-左-右"。
验算:A, B, D(叶), E(叶), C, F(叶) = ABDECF ✓
01// 树形: A 02// / \ 03// B C 04// / \ / 05// D E F 06void in(Node *p) { 07 if (p == NULL) return; 08 in(p->l); 09 cout << p->data; 10 in(p->r); 11}
中序遍历输出为( )。
考点:中序遍历输出(J2)。
实现要点:中序递归三步:判空 → 递归左 → 输出根 → 递归右——输出语句放在两次递归中间,这就是"根在中间"。
解析:树 A(B(D,E), C(F)):D → B → E → A → F → C = DBEAFC。✅ B
排除法:A 前序;C 后序;D DBEACF 是 C/F 顺序记反(中序里 F 在 C 前:C 的左子树 F 先访问)。
关联 · 中序(C2):对 BST 做中序 = 升序输出(L3 的基石)。
验算:左子树 DBE → A → 右子树 FC = DBEAFC ✓
01// 树形: A 02// / \ 03// B C 04// / \ / 05// D E F 06void post(Node *p) { 07 if (p == NULL) return; 08 post(p->l); 09 post(p->r); 10 cout << p->data; 11}
后序遍历输出为( )。
考点:后序遍历输出(J3)。
实现要点:后序递归三步:判空 → 递归左 → 递归右 → 输出根——输出放在两次递归之后,根最后访问。
解析:树 A(B(D,E), C(F)):D → E → B → F → C → A = DEBFCA。✅ A
排除法:B 中序;C 前序;D DEFCBA 顺序错(F 在 C 前、C 在 A 前)。
关联 · 后序(C3):表达式树的后序 = 后缀表达式——"先算子再算根"。
验算:左 DEB → 右 FC → 根 A = DEBFCA ✓
// 树形: // A // / \ // B C // / \ / // D E F // 前序 ABDECF、中序 DBEAFC、后序 DEBFCA
判断题:前序第一个节点是根,后序最后一个节点是根。
考点:三序对比(J4)。
实现要点:三序的唯一区别是输出语句的位置:前序在最前、中序在中间、后序在最后——抓住"根的位置",三序代码一次记全。
解析:前序第一个是根(最先访问根)、后序最后一个也是根(最后访问根)。✅ 正确
排除法:无(判断题)。混淆点:中序"根在中间"——前序后序的首尾都是根。
关联 · 前序中序定树(C6):前序首 = 根、后序尾 = 根——还原树的起点。
01// 层序遍历:队列保存节点,出队时输出并把左右孩子入队 02// 树形: A 03// / \ 04// B C 05// / \ / 06// D E F 07queue<Node*> q; 08q.push(root); 09while (!q.empty()) { 10 Node *p = q.front(); q.pop(); 11 cout << p->data; 12 if (p->l) q.push(p->l); 13 if (p->r) q.push(p->r); 14}
层序遍历输出为( )。
考点:层序遍历(J5)。
实现要点:层序 = 队列:根入队 → 循环"出队输出、左右孩子非空入队"——队列保证先入队的(上层)先出,逐层推进;用栈就会变深度优先(P3 的坑)。
解析:A → B,C → D,E,F = ABCDEF。✅ A
排除法:B 前序;C 中序;D ACBDEF 顺序错。
关联 · 层序(C4):BFS 在树上的应用——队列是层序的灵魂。
验算:A、BC、DEF = ABCDEF ✓
某二叉树:前序 = "ABDEC",中序 = "DBEAC"
由前序定根、中序分左右子树,可推出后序为( )。
考点:前序中序推后序(J6)。
实现要点:前序首 = 根 A;中序分左右:DBE | A | C;左子树前序 BDE、中序 DBE → B 根、D 左、E 右。后序 = 左后序 + 右后序 + 根 = DEB + C + A。
解析:后序 = DEBCA。✅ A
排除法:B DBEAC 是中序;C/D 顺序错。
关联 · 前序中序定树(C6):"前序取根、中序分边"递归到叶。
验算:左 DEB → 右 C → 根 A = DEBCA ✓
01struct Node { char data; Node *l, *r; }; 02 03// 后序遍历:左 → 右 → 根 04void post(Node *p) { 05 if (p == NULL) return; 06 post(p->l); 07 ______; 08 cout << p->data; 09}
横线处应填( )。
考点:遍历代码补全(J7)。
实现要点:后序 = 左 → 右 → 根:左递归后先递归右子树,最后输出——横线填 post(p->r)。
解析:✅ A
排除法:B 又递归左(重复左);C 提前输出根(变前序);D 直接返回(漏右子树)。
关联 · 后序(C3):输出在最后——三序补全题都考"输出语句的位置"。
01struct Node { int data; Node *l, *r; }; 02 03// 求二叉树的节点个数 04int cnt(Node *p) { 05 if (p == NULL) return 0; 06 return cnt(p->l) + cnt(p->r) + 1; 07}
树形(A 为根):
A
/ \
B C
/ \ /
D E F
该树共 个节点,判断题:cnt(root) 返回 。
考点:求节点个数(K1)。
实现要点:递归统计 = 左子树个数 + 右子树个数 + 1(自己),空树返回 0——递归三件套的"和式";写递归先写出口(空树 0),再写本层(+1)。
解析:6 个节点的树 → cnt(root) = 6。✅ 正确
排除法:无(判断题)。混淆点:与深度公式(max+1)别混——个数用加、深度用 max。
关联 · 递归求节点数(G3):
cnt(l) + cnt(r) + 1是标准式。
验算:左 3 + 右 2 + 1 = 6 ✓
01struct Node { int data; Node *l, *r; }; 02 03// 求深度:空树 0,否则 max(左,右) + 1 04int depth(Node *p) { 05 if (p == NULL) return 0; 06 return max(depth(p->l), depth(p->r)) + 1; 07}
树形(A 为根):
A
/ \
B C
/ \ /
D E F
该树深度为 (最远叶子到根的层数),判断题:depth(root) 返回 。
考点:求深度(K2)。
实现要点:深度 = max(左深, 右深) + 1,空树 0——取"较深的一边"再加自己这一层;与节点数的区别:深度用 max、个数用加法。
解析:A(B(D,E),C(F)):左深 2(B→D/E)、右深 2(C→F),max(2,2)+1 = 3。✅ 正确
排除法:无(判断题)。混淆点:左+右+1 是节点数公式(G3)——max vs 加法是高频混淆。
关联 · 递归求深度(G2):深度 = max+1——树的"高度"定义。
验算:max(2, 2) + 1 = 3 ✓
01struct Node { int data; Node *l, *r; }; 02 03// 求叶子数:叶子 = 左右都空 04int leaf(Node *p) { 05 if (p == NULL) return 0; 06 if (p->l == NULL && p->r == NULL) return 1; 07 return leaf(p->l) + leaf(p->r); 08}
树形(A 为根):
A
/ \
B C
/ \ /
D E F
该树的叶子是 D、E、F(没有孩子的节点)共 个,判断题:leaf(root) 返回 。
考点:求叶子数(K3)。
实现要点:叶子数递归:空树 0;左右皆空 = 叶子返回 1;否则 = 左叶子 + 右叶子——"叶子判定"是这段代码与求节点数的唯一区别。
解析:D、E、F 三个叶子 → leaf(root) = 3。✅ 正确
排除法:无(判断题)。混淆点:只有一个孩子空的节点不是叶子(如 C 只有左孩子 F)——必须两个都空。
关联 · 递归求叶子数(G4):
l==NULL && r==NULL是叶子判定式。
验算:D、E、F = 3 ✓
01struct Node { int data; Node *l, *r; }; 02 03// 求第 k 层节点数(根是第 1 层) 04int levelCnt(Node *p, int k) { 05 if (p == NULL || k < 1) return 0; 06 if (k == 1) return 1; 07 return levelCnt(p->l, k - 1) + levelCnt(p->r, k - 1); 08}
树形(A 为根):
A
/ \
B C
/ \ /
D E F
判断题:levelCnt(root, 3) 返回 (第三层有 D、E、F 三个节点)。
考点:第 k 层节点数(K4)。
实现要点:第 k 层 = 递归到 k==1 返回 1,否则往左右子树各传 k-1——"层数每次减 1"是参数设计的关键;k<1 或空树返回 0。
解析:第 3 层 = D、E、F 共 3 个。✅ 正确
排除法:无(判断题)。混淆点:层数从 1 数——k==1 是当前层,不是第 0 层。
关联 · 递归求深度(K2):深度是"最远层的层数"——k 递减与深度递增是一体两面。
验算:root 传 3 → 左右传 2 → 叶子层 1:D,E,F = 3 ✓
01struct Node { int data; Node *l, *r; }; 02 03// 交换左右子树(镜像) 04void mirror(Node *p) { 05 if (p == NULL) return; 06 swap(p->l, p->r); 07 mirror(p->l); 08 mirror(p->r); 09}
判断题:mirror 递归地把每棵子树的左右孩子交换——整棵树变成"镜像"。
考点:交换左右子树(K5)。
实现要点:镜像 = 后序式递归:先交换当前节点的左右指针,再递归进左右子树(此时左右已互换,递归"新左"即"旧右")——swap(p->l, p->r) 一行 + 两次递归。
解析:每个节点左右互换 → 整棵树镜像。✅ 正确
排除法:无(判断题)。混淆点:交换是"指针换"不是"值换"——子树整体对调。
关联 · 递归定义(G1):递归处理"根 + 左右子树"——镜像只是多一步 swap。
01// 判断满二叉树:每层都满 ⇔ 节点数 = 2^深度 - 1 02bool isFull(Node *p) { 03 return cnt(p) == (1 << depth(p)) - 1; 04}
树形(A 为根):
A
/ \
B C
/ \ /
D E F
该树共 6 节点、深度 3,,判断题:返回 false(不是满二叉树)。
考点:判断满二叉树(K6)。
实现要点:满树 ⇔ 节点数 == 2^深度 - 1(每层全满才有这么多节点)——用两个递归函数组合判断:cnt 与 depth。
解析:6 节点、深度 3: → 不是满树。✅ 正确
排除法:无(判断题)。混淆点:完全二叉树也可能是 6 节点(最后一层不齐)——满更严格。
关联 · 满二叉树节点数(B3): 是满树的"身份证"。
验算: → false ✓
01struct Node { int data; Node *l, *r; }; 02 03// 求二叉树最大值 04int maxVal(Node *p) { 05 if (p == NULL) return -1e9; 06 return max(p->data, max(maxVal(p->l), maxVal(p->r))); 07}
判断题:空节点返回极小值 ,保证不影响比较结果。
考点:求最大值(K7)。
实现要点:树的最大值 = max(自己, 左子树最大, 右子树最大)——空树返回一个极小值(-1e9)保证不影响比较;这是"递归维护最值"的标准技巧。
解析:空节点返回 充当"最值的垫底"。✅ 正确
排除法:无(判断题)。混淆点:极小值要小于所有可能的数据——数据范围 [-1e9, 1e9] 时选 -1e9 安全。
关联 · 递归三件套(K1~K3):max 型递归 = 深度公式的变体(取 max 不取和)。
01struct Node { int data; Node *l, *r; }; 02 03// BST 查找:小走左、大走右、相等命中 04bool find(Node *p, int x) { 05 if (p == NULL) return false; 06 if (p->data == x) return true; 07 return x < p->data ? find(p->l, x) : find(p->r, x); 08}
BST:5(根),左 3(左 2),右 8(左 6),判断题:find(root, 6) 的查找路径是 5 → 8 → 6。
考点:BST 查找(L1)。
实现要点:查找 = 小走左、大走右、相等命中:每次与当前节点比较,砍掉一半子树——递归版三行;空树返回 false。
解析:5 根,6 > 5 走右(8),6 < 8 走左(6)命中——路径 5→8→6。✅ 正确
排除法:无(判断题)。混淆点:递归返回的是"布尔"——命中 true、到底 false,逐层传回。
关联 · BST 查找(F2):查找路径 = 比较路径——"每次排除一半"。
验算:5 → 8 → 6 ✓
01struct Node { int data; Node *l, *r; }; 02 03// BST 插入:小走左、大走右,到空位落成叶子 04void insert(Node* &p, int x) { 05 if (p == NULL) { p = new Node; p->data = x; p->l = p->r = NULL; return; } 06 if (x < p->data) insert(p->l, x); 07 else insert(p->r, x); 08}
判断题:依次插入 5、3、8、6,6 落在 8 的左孩子位置。
考点:BST 插入(L2)。
实现要点:插入 = 沿查找路径走到空位,在空位建新节点——Node* &p 引用参数让"空指针处直接长出节点";新节点必是叶子。
解析:5 根;3 < 5 落左;8 > 5 落右;6 < 8 落 8 的左孩子。✅ 正确
排除法:无(判断题)。混淆点:引用 &p 是本题关键——不用引用则空位赋值不生效(值传递陷阱)。
关联 · BST 插入(F3):插入路径 = 查找路径——新值总是叶子。
验算:5(左3, 右8(左6)) ✓
01// 对 BST 5(左 3(左 2)、右 8(左 6))做中序遍历 02void in(Node *p) { 03 if (p == NULL) return; 04 in(p->l); 05 cout << p->data << ' '; 06 in(p->r); 07}
输出为( )。
考点:BST 中序有序(L3)。
实现要点:BST 中序 = 升序输出——中序的"左-根-右"配合 BST 的"左<根<右"天然排序;这是 BST 最常用的性质,也是验证 BST 的方法。
解析:树 5(左3(左2), 右8(左6)) 中序 = 2 3 5 6 8。✅ A
排除法:B 前序;C 顺序错;D 层序。
关联 · BST 中序有序(F4):中序遍历 = 免费排序。
验算:左 23 → 5 → 右 68 = 2 3 5 6 8 ✓
依次向空 BST 插入:4, 2, 6, 1, 3, 5, 7
构建完成后中序遍历输出为( )。
考点:构建后中序输出(L4)。
实现要点:顺序插入构建 BST:第一个是根,后面每个都沿"小左大右"落位——插入顺序只影响树形,不影响中序结果(中序永远有序)。
解析:插入 4,2,6,1,3,5,7 → 平衡树,中序 = 1 2 3 4 5 6 7。✅ A
排除法:B 前序;C 后序;D 层序。
关联 · BST 中序(L3):无论怎么插,中序都是升序——BST 的排序特性。
验算:全插入后中序 = 1 2 3 4 5 6 7 ✓
BST:8(左 3(右 6(左 4)),右 10)
查找 4 的路径是( )。
考点:BST 查找路径(L5)。
实现要点:查找路径 = 从根开始每次与当前值比较:目标小走左、大走右——路径就是"比较序列";手算时沿比较方向画箭头。
解析:8 根;4 < 8 走左(3);4 > 3 走右(6);4 < 6 走左(4)命中——路径 8 3 6 4。✅ A
排除法:B 走了右子树(10);C 从下往上(反了);D 漏了 6。
关联 · BST 查找(L1):路径题 = 查找代码的手工执行。
验算:8 → 3 → 6 → 4 ✓
01// 判断一棵树是否是 BST:中序遍历检查是否严格递增 02bool ok = true; 03int prev = INT_MIN; 04void check(Node *p) { 05 if (p == NULL) return; 06 check(p->l); 07 if (p->data <= prev) ok = false; 08 prev = p->data; 09 check(p->r); 10}
判断题:中序遍历 BST 应严格递增——出现"当前值 ≤ 前一个值"即判定非 BST。
考点:判断 BST(L6)。
实现要点:判 BST = 中序遍历检查严格递增:维护前一个访问值 prev,当前值 ≤ prev 即违规——"中序有序 ⇔ BST"的等价性反用。
解析:中序严格递增 = BST;出现 ≤ 前值即 false。✅ 正确
排除法:无(判断题)。混淆点:prev 初值要小于所有可能值(INT_MIN);只检查"左孩子<根<右孩子"不够(F1 的整子树要求)。
关联 · BST 定义(F1):判 BST 用中序递增——比逐子树检查简洁。
01// BST 最小值 = 一直向左走到底 02int minVal(Node *p) { 03 while (p->l != NULL) p = p->l; 04 return p->data; 05}
判断题:BST 的最小值在最左边的节点(左子树为空的节点)。
考点:BST 最小值(L7)。
实现要点:BST 最小值 = 一路向左走到底(左子树全更小)——循环 while (p->l) p = p->l;最大值对称:一路向右。
解析:最左节点 = 最小值。✅ 正确
排除法:无(判断题)。混淆点:最左节点不一定是叶子(它有右子树时)——但值一定最小。
关联 · BST 定义(F1):左小右大 → 最左最小、最右最大——找最值 。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[8] = {0, 1, 2, 3, 4, 5, 6, 7}; // 完全二叉树数组存储(a[0] 不用) 05 // 第 2 层的节点:下标 2、3 06 cout << a[2] << " " << a[3]; 07 return 0; 08}
单选题:程序输出是?
考点:第二层的节点(M1)。
解析:第 2 层 = 下标 → 输出 2 3。正确答案 A。
实现要点:第 层的下标范围是 。手算:根(第 1 层)下标 1,第 2 层 2、3。
排除法:B 是第 3 层前两个;C 含根;D 是第 3 层后两个。
关联 · 完全二叉树的数组表示(F5):下标公式的直接应用。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int i = 5; // 节点下标(根为 1) 05 int parent = i / 2; // 父节点 06 int left = 2 * i; // 左孩子 07 cout << parent << " " << left; 08 return 0; 09}
单选题:程序输出是?
考点:父子下标计算(M2)。
解析:节点 5 的父 、左孩子 → 2 10。正确答案 A。
实现要点:父 = 、左孩子 = 、右孩子 = 。手算:三个公式代入即可。
排除法:B 父算错;C 右孩子混入;D 无依据。
关联 · 完全二叉树的下标关系(F6):公式的代码版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 7; // 节点个数 05 int depth = 0; 06 while ((1 << depth) <= n) depth++; // 2^depth <= n 的最大层 07 cout << depth; // 完全二叉树深度 08 return 0; 09}
单选题:程序输出是?
考点:完全二叉树深度计算(M3)。
解析:、 → 深度 3。正确答案 A。
实现要点:深度 = ;代码用 while ((1 << depth) <= n) depth++。手算:数 落在哪两个 2 的幂之间。
排除法:B(2)是 的深度;C 是节点数;D 多算一层。
关联 · 完全二叉树的定义与基本性质(B 组):深度公式的代码版。
单选题:完全二叉树数组表示的特点是?
考点:数组表示的连续性(M4)。
解析:完全二叉树数组表示 = 下标 连续存放、中间无空缺——这是"完全"二字的体现。正确答案 A。
排除法:B 显然错误;C 与排序无关;D——数组表示恰是为了不用链表。
关联 · 完全二叉树的数组表示(F5):连续性是核心特征。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[8] = {0, 10, 20, 30, 40, 50, 60, 70}; // 完全二叉树数组存储 05 int i = 3; // 节点下标 06 cout << a[2 * i]; // 左孩子的值 07 return 0; 08}
单选题:程序输出是?
考点:左孩子的值(M5)。
解析:节点 3 的左孩子下标 ,值 60。正确答案 A。
实现要点:左孩子值 = a[2 * i]。手算:,。
排除法:B 是节点 3 本身;C 是 ;D 是右孩子。
关联 · 父子下标计算(M2):左孩子公式的取值版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[8] = {0, 1, 2, 3, 4, 5, 6, 7}; // 完全二叉树数组存储 05 int i = 3; // 当前节点下标 06 cout << a[______] << " " << a[______]; // 输出节点 i 的左右孩子 07 return 0; 08}
单选题:两处横线依次应填入?
考点:补全孩子下标(M6)。
解析:左右孩子 = 、。运行:节点 3 的孩子 、。正确答案 A。
实现要点:孩子公式三件套:左 、右 、父 。手算:代入验证。
排除法:B 是父与父+1;C/D 无依据。
关联 · 完全二叉树的下标关系(F6):公式填空版。
01struct Node { char data; Node *l, *r; }; 02 03// 前序遍历:根 → 左 → 右 04void pre(Node *p) { 05 if (p == NULL) return; 06 cout << p->data; 07 pre(p->l); 08 ______; 09}
横线处应填( )。
考点:补全前序遍历(N1)。
实现要点:前序 = 根 → 左 → 右:输出后先递归左、再递归右——横线填 pre(p->r)。
解析:✅ A
排除法:B 重复左;C 重复输出;D 漏右子树。
关联 · 前序(C1):三行顺序 = "根左右"——补全题考的就是输出语句的位置。
01struct Node { char data; Node *l, *r; }; 02 03// 中序遍历:左 → 根 → 右 04void in(Node *p) { 05 if (p == NULL) return; 06 ______; 07 cout << p->data; 08 in(p->r); 09}
横线处应填( )。
考点:补全中序遍历(N2)。
实现要点:中序 = 左 → 根 → 右:输出前先递归左——横线填 in(p->l)。
解析:✅ A
排除法:B 先右(变反中序);C 提前输出;D 漏左子树。
关联 · 中序(C2):左递归在最前——"根在中间"。
01struct Node { int data; Node *l, *r; }; 02 03// 求深度:空树 0,否则 max(左,右) + 1 04int depth(Node *p) { 05 if (p == NULL) return 0; 06 return ______; 07}
横线处应填( )。
考点:补全求深度(N3)。
实现要点:深度 = max(左, 右) + 1——横线填整个表达式;用 max 不用加法(加法是求节点数)。
解析:✅ A
排除法:B 左+右+1 是节点数公式;C 忘了 +1;D 同 B 变体。
关联 · 求深度(K2):max+1 是深度、和+1 是个数——两公式成对。
01struct Node { int data; Node *l, *r; }; 02 03// 求节点数:空树 0,否则 左 + 右 + 1 04int cnt(Node *p) { 05 if (p == NULL) return 0; 06 return ______; 07}
横线处应填( )。
考点:补全求节点数(N4)。
实现要点:节点数 = 左 + 右 + 1(自己)——横线填 cnt(p->l) + cnt(p->r) + 1。
解析:✅ A
排除法:B 忘了 +1(漏根);C 是深度公式;D 漏右子树。
关联 · 求节点数(K1):"和 + 1"——+1 是数自己。
01struct Node { int data; Node *l, *r; }; 02 03// 求叶子数 04int leaf(Node *p) { 05 if (p == NULL) return 0; 06 if (______) return 1; 07 return leaf(p->l) + leaf(p->r); 08}
横线处应填( )。
考点:补全求叶子数(N5)。
实现要点:叶子 = 左右孩子都空——横线填 p->l == NULL && p->r == NULL(&& 两个条件都查)。
解析:✅ A
排除法:B 条件反(非叶子返回 1);C/D 只查一边(单孩子节点会误判为叶子)。
关联 · 求叶子数(K3):
&&是叶子判定的灵魂——"两个都空"。
01struct Node { int data; Node *l, *r; }; 02 03// BST 插入 04void insert(Node* &p, int x) { 05 if (p == NULL) { 06 p = new Node; 07 p->data = x; p->l = p->r = NULL; 08 return; 09 } 10 if (x < p->data) insert(p->l, x); 11 else ______; 12}
横线处应填( )。
考点:补全 BST 插入(N6)。
实现要点:BST 插入分支:小走左、大(或等)走右——横线填 insert(p->r, x)。
解析:✅ A
排除法:B 又走左(大值插错边);C p->r = x 类型错;D 直接返回(大值丢失)。
关联 · BST 插入(L2):插入与查找同路——"小左大右"。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[8] = {0, 1, 2, 3, 4, 5, 6, 7}; // 完全二叉树数组存储(a[0] 不用) 05 int i = 6; // 当前节点下标 06 cout << a[______]; // 输出节点 i 的父节点值 07 return 0; 08}
单选题:横线处应填入?
考点:补全父节点下标(N7)。
解析:父节点下标 = i / 2(整除)。运行:。正确答案 A。
实现要点:C++ 整数除法自动向下取整——6 / 2 = 3 正是父节点下标。手算:对照 F6 的公式。
排除法:B 是左孩子公式;C/D 无依据。
关联 · 完全二叉树的下标关系(F6):父公式填空版。
层序遍历(队列):完全二叉树数组存:10, 20, 30, 40, 50, 60, 70(下标 1 起)
按层输出 = 数组下标顺序 1..7,输出为( )。
考点:层序输出(O1)。
实现要点:完全二叉树数组存时,层序 = 数组下标顺序(1..n)——顺序存储让层序遍历退化成顺序输出;这也是数组存树的优势。
解析:数组 1..7 直接输出 = 10 20 30 40 50 60 70。✅ A
排除法:B 前序;C 中序;D 后序。
关联 · 层序(C4):数组树的层序 = 下标序——存储与遍历的巧合。
前序 + 中序重建二叉树:
前序 = "ABDECF",中序 = "DBEAFC"
重建后的树:A 为根,B 的左右孩子是 D/E,C 的左孩子是 F
判断题:重建时先取前序第一个为根,再在中序里找根位置分左右子树,递归建。
考点:前序中序重建(O2)。
实现要点:重建算法:前序第一个 = 根 → 中序里找根的位置分左右两段 → 递归建左右子树(前序也按中序切出的长度切段)——"前序取根、中序分边、递归建树"。
解析:前序 ABDECF + 中序 DBEAFC 重建出原树。✅ 正确
排除法:无(判断题)。混淆点:重建关键是中序定位根——前序后序不能重建(无左右划分依据)。
关联 · 前序中序定树(C6):重建 = C6 的代码实现——真题高频。
权值 {2, 3, 4, 5} 构造哈夫曼树(每次合并最小的两个):
2+3=5 → {4, 5, 5};4+5=9 → {5, 9};5+9=14
WPL = 2*3 + 3*3 + 4*2 + 5*1 = 28
判断题:构造过程中新节点权值 = 两个子节点权值之和,最终根权值 = 全部权值和。
考点:哈夫曼建树模拟(O3)。
实现要点:哈夫曼构造循环:集合取最小两个合并 → 新节点(权和)放回 → 直到剩一个——每次合并后集合少一个元素;新节点权值 = 子节点权值和,最终根 = 全权和。
解析:{2,3,4,5} → 合并 2+3=5 → {4,5,5} → 4+5=9 → {5,9} → 5+9=14。✅ 正确
排除法:无(判断题)。混淆点:合并顺序可能不唯一,但 WPL 恒最小(= 28)。
关联 · 哈夫曼构造(E5):"最小两合并"——贪心的核心动作。
验算:2+3=5、4+5=9、5+9=14 ✓
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[8] = {0, 1, 2, 3, 4, 5, 6, 7}; // 完全二叉树数组存储 05 cout << a[1] << endl; // 第 1 层 06 cout << a[2] << " " << a[3] << endl; // 第 2 层 07 cout << a[4] << " " << a[5] << " " << a[6] << " " << a[7] << endl; // 第 3 层 08 return 0; 09}
单选题:程序输出是?
考点:完全二叉树分层输出(O4)。
解析:第 1 层 1、第 2 层 2 3、第 3 层 4 5 6 7——按层下标范围输出。正确答案 A。
实现要点:第 层下标 ,逐层打印。手算:、、。
排除法:B 是层序一行版;C 是逆序;D 层内下标错位。
关联 · 第二层的节点(M1):单层输出的完整版。
依次插入 7, 2, 9, 1, 5 到 BST,中序遍历输出 = 排序结果
输出为( )。
考点:BST 中序排序验证(O5)。
实现要点:BST 中序 = 升序——插入乱序数据后,中序遍历就是"免费排序";这是验证 BST 正确性的标准手段。
解析:7,2,9,1,5 插入后中序 = 1 2 5 7 9。✅ A
排除法:B 前序;C 降序(右根左);D 乱序。
关联 · BST 中序有序(F4):插入任意顺序、中序永远升序——BST 的排序价值。
验算:排序结果 1 2 5 7 9 ✓
01// 前序遍历(缺少递归出口): 02void pre(Node *p) { 03 cout << p->data; 04 pre(p->l); 05 pre(p->r); 06}
判断题:没有 if (p == NULL) return; 出口,遇到叶子节点会继续对空指针解引用导致崩溃。
考点:递归缺出口(P1)。
实现要点:递归必须有出口(本题 = 空指针判断):没有 if (p == NULL) return;,递归会一路解引用空指针——叶子节点的 p->l 是 NULL,访问 NULL->data 崩溃。
解析:缺出口 → 空指针解引用崩溃。✅ 正确
排除法:无(判断题)。混淆点:递归两要素:出口 + 规模缩小——缺一不可。
关联 · 递归定义(G1):空树是递归定义的基例——出口代码就是基例。
01// 中序遍历(左右写反): 02void in(Node *p) { 03 if (p == NULL) return; 04 in(p->r); // 先右 05 cout << p->data; 06 in(p->l); // 后左 07}
判断题:这样输出的是"降序"(对 BST 而言是 右-根-左 遍历),不是标准中序。
考点:左右子树写反(P2)。
实现要点:中序的左右递归顺序不能换:先右后左 = "右-根-左"(对 BST 输出降序)——三序遍历的顺序就是代码的顺序,写反即错。
解析:in(p->r) 在前 → 降序(右根左),不是标准中序。✅ 正确
排除法:无(判断题)。混淆点:把 p->r 写成 p->l 是最常见笔误——两个递归调用名字相近。
关联 · 中序(C2):左 → 根 → 右——顺序 = 语义。
01// 层序遍历误用栈(stack)代替队列(queue): 02stack<Node*> st; 03st.push(root); 04while (!st.empty()) { 05 Node *p = st.top(); st.pop(); 06 cout << p->data; 07 if (p->l) st.push(p->l); 08 if (p->r) st.push(p->r); 09}
判断题:用栈会变成深度优先(后进先出),输出不再是层序。
考点:层序用栈(P3)。
实现要点:层序必须队列:栈是 LIFO——出栈的是最后入的孩子(深层),变成深度优先;"容器选错 = 遍历变种"是容器类题的通用教训。
解析:栈 → 深度优先(后进先出),输出不再是层序。✅ 正确
排除法:无(判断题)。混淆点:DFS 用栈、BFS/层序用队列——容器与遍历严格配对(第 8 章 B6/C7)。
关联 · 层序(C4):队列是层序的"法定容器"。
01// 求深度(缺少空树判断): 02int depth(Node *p) { 03 return max(depth(p->l), depth(p->r)) + 1; // 无 p == NULL 出口 04}
判断题:没有空树出口,递归到叶子时会解引用空指针——崩溃。
考点:空节点访问(P4)。
实现要点:递归求深度必须有空树出口(p == NULL 返回 0)——叶子节点的孩子是 NULL,没有出口就 NULL->l 崩溃;"判空在第一步"是所有树递归的铁律。
解析:缺空树出口 → 崩溃。✅ 正确
排除法:无(判断题)。混淆点:出口返回值要与公式自洽(深度返回 0、节点数返回 0、叶子数返回 0)。
关联 · 求深度(K2):出口(空树 0)+ 递推(max+1)——两行缺一不可。
下列说法错误的是( )。
考点:综合判断(P5)。
解析:D 错误——后序遍历的最后一个节点才是根(根最后访问);第一个是左子树最左下的叶子。✅ D
排除法:A 前序首 = 根 ✓;B BST 中序升序 ✓;C 完全二叉树第 个节点 ✓。
关联 · 本章串联:A(C1)、B(F4)、C(B 组性质)、D(C3)——综合题 = 细节判断的集合。