空间优化 Morris 遍历算法 它能以 O(1) 额外空间完成二叉树中序遍历,适合内存敏感场景:
java
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class MorrisTraversal {
public static void inOrder(TreeNode root) {
TreeNode curr = root;
while (curr != null) {
if (curr.left == null) {
// 无左子树,直接访问当前节点
System.out.print(curr.val + " ");
curr = curr.right;
} else {
// 寻找前驱节点
TreeNode predecessor = curr.left;
while (predecessor.right != null && predecessor.right != curr) {
predecessor = predecessor.right;
}
if (predecessor.right == null) {
// 建立临时线索
predecessor.right = curr;
curr = curr.left;
} else {
// 删除线索并访问节点
predecessor.right = null;
System.out.print(curr.val + " ");
curr = curr.right;
}
}
}
}
public static void main(String[] args) {
/* 构建测试树:
4
/ \
2 6
/ \ /
1 3 5
*/
TreeNode root = new TreeNode(4);
root.left = new TreeNode(2);
root.right = new TreeNode(6);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(3);
root.right.left = new TreeNode(5);
System.out.println("Morris 中序遍历:");
inOrder(root); // 输出: 1 2 3 4 5 6
}
}
🎯 高级技巧解析:
-
空间压缩原理
利用叶子节点的空指针存储临时线索,将空间复杂度从 O(n)(递归栈/显式栈)优化到 O(1)
-
关键操作
- 寻找前驱节点:定位当前节点左子树的最右节点
- 建立临时线索:将前驱节点的右指针指向当前节点
- 拓扑恢复:遍历后自动恢复树结构,避免内存泄漏
-
复杂度分析
- 时间复杂度:O(n)(每个边被访问不超过 3 次)
- 空间复杂度:O(1)(仅用 2 个临时指针)
-
适用场景
- 内存受限的嵌入式系统
- 超大规模树结构遍历
- 需要避免递归栈溢出的场景
💡 进阶应用方向:
- 前序遍历变种:调整访问节点的时机即可实现
- 反向遍历:通过镜像操作处理右子树优先的情况
- 迭代器模式:封装为懒加载迭代器处理流式数据
此技巧展示了如何通过指针操作和拓扑变换来实现空间复杂度突破,是树结构遍历的经典优化方案。