递归实现 swapLeftRight 的核心是先递归处理左右子树再交换指针,终止条件为 root == nullptr;推荐用 std::swap 安全交换指针,避免手动临时变量引发智能指针异常;非递归需用 std::stack 存指针并判空;测试须覆盖空树、单节点、偏斜树等边界。

递归实现 swapLeftRight 是最直观的方式
核心思路是:对每个节点,先递归处理左右子树,再交换它们的指针。注意必须在递归调用之后再交换,否则会提前破坏子树结构,导致只换根、不换后代。
常见错误是写成「先交换再递归」,结果只翻转了顶层,深层节点完全没动;或者递归时传入了未初始化的空指针,触发段错误。
- 函数签名建议为
void swapLeftRight(TreeNode* root),接受原始指针,不需返回新树 - 递归终止条件必须是
root == nullptr,不能漏掉单边为空的情况(比如只有左子树时,右子树为nullptr也要参与交换) - 交换语句用
std::swap(root->left, root->right)更安全,比手动临时变量少出错
std::swap 比手写临时变量更可靠
有人习惯写三行临时变量交换:
TreeNode* tmp = root->left; root->left = root->right; root->right = tmp;
这在大多数情况下没问题,但若 TreeNode* 是自定义智能指针类型(如 std::unique_ptr<treenode></treenode>),手动赋值可能引发所有权转移异常或重复释放。而 std::swap 对原生指针和主流智能指针都有特化,行为一致且无副作用。
立即学习“C++免费学习笔记(深入)”;
使用场景上,只要节点指针类型支持移动或复制语义,std::swap 都适用;若用的是裸指针,它也等价于高效交换地址值。
非递归版本要注意栈中存的是节点指针,不是值
用 std::stack<treenode></treenode> 做 DFS 迭代时,压栈的是当前节点地址,每次弹出后直接交换其左右指针,再把非空子节点压入——顺序无关紧要(先左后右或先右后左都行),因为交换动作不依赖遍历顺序。
容易踩的坑是误把 stack<treenode></treenode> 当作存储节点副本,导致交换的只是栈里拷贝,原树毫发无损;或者忘记判空就访问 top()->left,触发空指针解引用。
- 务必用
std::stack<treenode></treenode>,不是TreeNode - 每次
pop()后立即检查node != nullptr再操作 - 交换完左右指针后,把
node->left和node->right(此时已互换)都压栈,确保所有节点都被访问到
测试时别只用满二叉树,要覆盖边界情况
很多人验证时只跑 1-2-3-4-5-6-7 这样的完全二叉树,看起来翻转正确,但一遇到 nullptr 分布不均的结构就崩。典型漏测场景包括:空树、单节点、只有左子树、只有右子树、深度为 1 的退化树。
一个简单但有效的验证方式是:翻转两次应还原原树(前提是节点值唯一且可比较)。但这对含重复值的树不充分,所以最好额外打印中序/层序遍历结果对比。
真正难调试的是指针悬空问题——比如某次交换后某个子树被意外释放,后续访问时崩溃位置远离交换代码,得靠 ASan 或反复检查内存生命周期。


















