LeetCode 590.N叉树后序遍历代码错误排查及编程建议求助
LeetCode 590.N叉树后序遍历问题求助
我在解决LeetCode 590.N叉树后序遍历问题时,编写的C++代码通过了部分测试用例,但在测试用例28(大尺寸用例)报错,无法直接调试,现求助以下两个问题:
- 我的代码存在什么错误?
- 关于编码风格和练习方法有哪些建议?
我的代码如下:
/* // Definition for a Node. class Node { public: int val; vector<Node*> children; // 벡터노드가 자식 노드들을 배열로 가지고 있다. Node() {} Node(int _val) { val = _val; } Node(int _val, vector<Node*> _children) { val = _val; children = _children; } }; */ class Solution { public: vector<int> postorder(Node* root) { // 이진트리가 아니다 // 후순위 탐색이다. // 자식부터 탐색한다는 점에서 우선 dfs인듯하다 -> stack 활용 vector<Node*> stack; Node* current = root; vector<int> ans; if(!current){ return ans; } stack.push_back(current); // stack에 넣기 while(!stack.empty()) { current = stack.back(); if(!(current->children).empty()){ // 자식이 있는 경우 int n = (current->children).size(); for(int i = n-1; i>=0;i--){ stack.push_back((current->children)[i]); } } else{ ans.push_back(current->val); // 자식이 없는 경우 int temp = (stack.back())->val; stack.pop_back(); bool chk = false; if(!stack.empty()){ current = stack.back(); // 3이 걸림 vector<Node*> v = current->children; int m = v.size(); for(int i = 0; i < m; i++){ // 이걸 반복해야할텐데 if((v[i]->val) == temp){ chk = true; } } while(chk&&!stack.empty()) { // 쭉 딸려 올라가도록 ans.push_back(current->val); int temp = (stack.back())->val; stack.pop_back(); chk = false; if(!stack.empty()){ current = stack.back(); // 3이 걸림 vector<Node*> v = current->children; int m = v.size(); for(int i = 0; i < m; i++){ // 이걸 반복해야할텐데 if((v[i] ->val) == temp){ chk = true; } } } } // 3에서 탈출 } } } return ans; } };
我遇到的核心难点是确定何时从栈中移除节点,因此用布尔值chk实现了回溯逻辑,但现在无法定位问题。
1. 代码错误分析
- 重复压入子节点:每次循环到有子节点的节点时,都会把它的所有子节点重新压入栈。比如第一次处理节点A时压入子节点B、C,下次循环又会再次处理A(因为A还在栈顶),再次压入B、C,导致栈中出现大量重复节点,最终遍历逻辑混乱,结果错误。
- 用节点值判断父子关系的逻辑错误:代码中通过
v[i]->val == temp判断当前节点是否是父节点的子节点,但若树中存在值相同的节点,这个判断会失效,导致错误的回溯。正确的做法是直接比较节点指针,而非节点值。 - 回溯逻辑的变量覆盖问题:在内部while循环中,重新定义了
int temp = (stack.back())->val;,覆盖了外部的temp变量,导致后续判断逻辑出错。 - 未标记节点是否已处理:迭代实现后序遍历的核心是区分节点是否已被访问过。你的代码没有标记节点状态,导致有子节点的节点会被反复处理,无法正确触发后序的“先处理所有子节点,再处理自身”的逻辑。
2. 编码风格与练习建议
编码风格优化
- 统一注释语言:代码中混用了韩文和中文注释,建议统一为中文(或英文),保持代码可读性。
- 变量命名更具语义:比如
stack可以改为nodeStack,chk改为isLastChildProcessed,temp改为processedNodeVal或直接用节点指针,让变量含义一目了然。 - 避免重复代码:回溯时判断子节点的逻辑重复出现,可以提取成一个辅助函数,比如
bool isLastProcessedChild(Node* parent, Node* child),减少代码冗余。 - 简化表达式:
(current->children).empty()可以直接写成current->children.empty(),(current->children)[i]简化为current->children[i],提升代码简洁度。
练习方法建议
- 先写递归版本,再转迭代:N叉树后序遍历的递归版本非常直观,先递归处理所有子节点,再加入当前节点值。先实现递归版本验证逻辑正确性,再基于递归的调用栈思路改造为迭代版本,更容易理解。
- 学习迭代后序的标准写法:常用的迭代方法是用栈存储
节点+访问标记(比如用pair<Node*, bool>,bool标记是否已访问)。第一次压入节点时标记为未访问,弹出未访问节点时,重新压入标记为已访问的节点,再逆序压入所有子节点;弹出已访问节点时,将值加入结果。这种方法逻辑清晰,不易出错。 - 构造小测试用例调试:针对大测试用例无法调试的问题,自己构造小的测试用例,比如包含重复值的树、多层嵌套的树、只有根节点的树等,手动模拟栈的执行过程,定位逻辑错误。
- 逐步调试:在本地IDE中开启调试模式,逐步执行代码,观察栈的变化和结果数组的生成过程,更容易发现重复压栈、错误回溯等问题。
内容的提问来源于stack exchange,提问作者my_first_step
相关产品推荐
相关产品推荐

