morris后序遍历核心难点在于必须翻转左子树前驱到当前节点的临时右链以构造逆后序访问路径,而非直接套用前序/中序模板;翻转时机(pred→right == cur时)、边界(tail ≠ current)、指针安全(只改right、需缓存原始值、翻转后立即还原)缺一不可。

Morris后序遍历的核心难点在哪
直接套用前序/中序的Morris模板会错——后序要求“左右根”,而Morris遍历天然按“根右左”逆序构造路径,必须靠翻转局部链表来模拟。这不是加个reverse()就能解决的,关键在翻转时机和边界判断。
如何安全地翻转临时链表而不破坏结构
每次找到线索节点(即当前节点的前驱)后,需从predecessor开始,沿right指针一路向右,把这段“右链”原地翻转;遍历完再翻回去。漏翻或翻错方向会导致后续线索断裂。
- 翻转起点是
predecessor,终点是current(不含) - 翻转时只改
right指针,不碰left - 翻回操作必须严格复原——用同一段代码反向执行
- 若
current->left == nullptr,跳过整个翻转逻辑
什么时候该输出节点值
只有两种情况能安全输出:一是节点无左子树(current->left == nullptr),直接访问;二是刚完成一次翻转并遍历完右链后,此时current的左子树已全部处理完毕,可输出current本身。
- 输出前必须确认该节点不会再被作为前驱访问——即它的
right指针已被还原为nullptr - 不能在翻转过程中输出,否则顺序错乱
- 常见错误:把“翻转完立即输出
predecessor”当成后序,实际那是中序变体
C++实现中容易崩的指针细节
所有right指针操作都隐含风险:线索可能指向任意节点,predecessor->right = current之后,predecessor的原始right值就丢了。必须用临时变量存好原始right,否则翻转时找不到终点。
- 声明
TreeNode* tail = predecessor;后,要用while (tail->right != current)找终点,而不是while (tail->right) - 翻转循环里,每步都要先缓存
tail->right,再改指针,否则断链 - 最后一步还原时,
tail->right必须设为nullptr,不是保留旧值 - 递归式思维在这里完全失效——Morris本质是手动模拟栈,所有状态都在指针里
真正难的不是写对第一次遍历,而是保证第N次访问时left/right关系依然自洽。多跑两组带重复节点或单边树的数据,很快会暴露指针没清干净的问题。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











