镜像翻转必须原地交换左右指针,不新建节点;递归需先处理子树再交换,终止条件仅为 if (!root) return;迭代法须判空后入栈并及时交换。

镜像翻转必须原地交换,不能新建节点
直接交换每个节点的 left 和 right 指针,不分配新 TreeNode 对象。否则就不是“原地”,空间复杂度会从 O(h)(递归栈)变成 O(n)(新树内存)。常见错误是写成「创建新节点并赋值」,这本质是复制而非翻转。
典型误写:
return new TreeNode(root->val, mirror(root->right), mirror(root->left));——这是构造新树,不符合题意。
- 正确做法:只改指针指向,
swap(root->left, root->right)或手动临时变量交换 - 必须先递归处理子树,再交换;若先交换再递归,会把左子树传给右子树的递归调用,逻辑错乱
- 空节点(
nullptr)直接返回,不操作
递归实现要处理好边界和返回值
函数签名通常为 void mirrorTree(TreeNode* root),返回 void 更符合“原地”语义。若定义为 TreeNode* 返回类型(如 LeetCode 常见写法),也应返回原 root 指针,而非新地址。
关键点:
- 递归终止条件只有
if (!root) return;,不需要额外判断叶子节点 - 左右子树递归调用顺序无关(
mirrorTree(root->left)和mirrorTree(root->right)可互换),但交换操作必须放在递归调用之后 - 如果用
swap,需确保包含<utility></utility>;手写交换更稳妥:TreeNode* tmp = root->left;<br>root->left = root->right;<br>root->right = tmp;
迭代写法容易漏掉空指针检查
用栈模拟递归时,常见错误是在入栈前没判空,导致压入 nullptr,后续解引用崩溃。正确做法是:只对非空子节点入栈,并在出栈后立即交换其左右指针。
- 推荐用
stack<treenode></treenode>,初始 push 根节点(若非空) - 每次 pop 后,先 swap 当前节点的
left/right,再分别检查并 push 非空的left和right - 错误示例:
st.push(root->left); st.push(root->right);—— 未判空,运行时崩
测试时要注意翻转后树结构是否真正镜像
仅打印根节点值看不出问题。必须验证路径:比如原树中从根出发的左-左路径,在镜像树中应变为右-右路径。常见疏忽是只测单层或满二叉树,漏掉一侧为空的情况。
- 构造测试用例:
root = [1,2,3,null,4]→ 镜像后应为[1,3,2,4,null](注意4原在左子树的右,翻转后应在右子树的左) - 调试技巧:在交换前后加日志,输出
root->val、root->left ? root->left->val : -1、root->right ? root->right->val : -1 - 别依赖中序遍历是否对称来验结果——镜像树的中序序列一般不相等,要用层序或手动走路径比对
实际写的时候,最易卡住的是递归顺序和空指针处理,这两个点错一个,整棵树就乱了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











