前序、中序、后序的区别在于访问节点的时机:前序先访问再递归左右,中序先左再访问再右,后序最后访问;关键看visit(node)在递归调用中的位置。

DFS遍历顺序怎么选:前序/中序/后序的区别在哪
二叉树DFS本质是递归访问顺序的差异,不是算法逻辑不同。关键在“访问节点”这一步放在递归左右子树的什么位置:
-
前序:先处理当前节点(比如打印值),再递归左、右子树 -
中序:先递归左子树,再处理当前节点,最后递归右子树(BST中序结果天然有序) -
后序:先递归左右子树,最后处理当前节点(适合释放内存、计算子树大小等依赖子树结果的场景)
别硬记口诀,直接看代码里 visit(node) 这行写在哪——它在哪,就是哪种序。
递归实现必须检查空指针,否则运行时崩溃
C++里对空指针解引用是未定义行为,segfault 或静默错误都可能。所有递归入口第一件事必须是判空:
void preorder(TreeNode* node) {
if (!node) return; // 必须有!漏掉就崩
cout val left);
preorder(node->right);
}
常见错误是只在调用处检查(比如 if (root) preorder(root)),但递归内部不检查——子树可能为空,node->left 就是 nullptr,下一步解引用必挂。
非递归DFS要用stack,但注意压栈顺序
用 std::stack 模拟递归调用栈时,顺序容易搞反。比如前序遍历要“先访问根,再左再右”,但栈是后进先出,所以得先压右子树,再压左子树:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
void preorder_iterative(TreeNode* root) {
if (!root) return;
stack<treenode> s;
s.push(root);
while (!s.empty()) {
TreeNode* node = s.top(); s.pop();
cout val right) s.push(node->right); // 先压右
if (node->left) s.push(node->left); // 后压左 → 左先弹出
}
}</treenode>
压错顺序会导致遍历结果变成“根→右→左”。中序/后序的非递归写法更复杂,涉及额外标记或双栈,日常开发优先用递归,除非明确要求避免栈溢出。
DFS找路径或判断存在性时,记得及时返回
如果目标是“找到某个值就停止”,递归函数必须设计成带返回值(如 bool),并在子树找到后立刻 return true,否则会白跑完所有分支:
bool findValue(TreeNode* node, int target) {
if (!node) return false;
if (node->val == target) return true;
return findValue(node->left, target) || findValue(node->right, target);
}
这里 || 的短路特性保证左子树找到就不再进右子树。但若写成两个独立调用再判断,就失去剪枝效果;更隐蔽的坑是忘了在递归调用后加 return,导致函数末尾无返回值——C++编译器未必报错,但行为未定义。
实际写的时候,节点结构体有没有 left/right 成员、是否用智能指针管理内存、是否需要传引用修改状态——这些细节比遍历框架本身更容易出问题。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










