Morris遍历算法(二叉树遍历)
字数 1341 2025-11-08 10:03:34
Morris遍历算法(二叉树遍历)
描述
Morris遍历算法是一种可以在O(n)时间内完成二叉树遍历,且仅使用O(1)额外空间的算法。它通过修改树中的临时指针(遍历结束后恢复)来避免使用栈或递归,适用于中序、前序遍历(后序遍历较复杂)。核心思想是利用叶子节点的空指针指向后继节点,从而在遍历时能回溯到上层节点。
解题过程
-
问题分析
- 常规二叉树遍历(递归/迭代)需要O(h)的栈空间(h为树高)。
- Morris遍历通过线索二叉树思想,将空闲指针用于记录回溯路径,实现空间复杂度O(1)。
-
中序遍历的Morris算法步骤
- 初始化当前节点
cur为根节点。 - 当
cur不为空时循环:- 若
cur无左子树:- 输出
cur的值(访问当前节点)。 - 将
cur指向右子树(cur = cur.right)。
- 输出
- 若
cur有左子树:- 找到
cur的前驱节点pre(即左子树的最右节点):pre = cur.left- 循环向右移动
pre,直到pre.right为空或指向cur(避免死循环)。
- 若
pre.right为空:- 将
pre.right指向cur(建立临时回溯指针)。 cur向左移动(cur = cur.left)。
- 将
- 若
pre.right指向cur(说明已访问过左子树):- 断开临时指针:
pre.right = null。 - 输出
cur的值(此时左子树已处理完)。 cur向右移动(cur = cur.right)。
- 断开临时指针:
- 找到
- 若
- 初始化当前节点
-
示例演示(中序遍历)
以二叉树[1,2,3,4,5]为例(根为2,左子树为1,右子树为4、3、5):- 步骤1:
cur=2,左子树存在,找到前驱节点1(最右节点),将1.right指向2。 - 步骤2:
cur=1,无左子树,输出1,cur移至1.right(即2)。 - 步骤3:
cur=2,左子树存在且前驱1.right指向2,断开指针,输出2,cur移至右子树4。 - 步骤4:
cur=4,左子树存在,找到前驱节点3,将3.right指向4。 - 步骤5:
cur=3,无左子树,输出3,cur移至3.right(即4)。 - 步骤6:
cur=4,左子树存在且前驱3.right指向4,断开指针,输出4,cur移至右子树5。 - 步骤7:
cur=5,无左子树,输出5,遍历结束。
输出顺序为1,2,3,4,5(正确中序)。
- 步骤1:
-
前序遍历的调整
- 与中序遍历区别:在第一次访问节点时立即输出(即建立临时指针前)。
- 步骤调整:
- 当
cur有左子树且前驱pre.right为空时,输出cur并建立指针。 - 当
cur无左子树时,输出cur后直接右移。
- 当
-
关键点总结
- 时间复杂度:每个节点被访问两次(一次找前驱,一次遍历),但每个前驱节点最多被找两次,总操作次数为O(n)。
- 空间复杂度:仅使用常数级额外变量(O(1))。
- 注意事项:遍历过程中临时修改指针,结束后恢复原树结构(已自动断开临时指针)。
通过Morris算法,可在不牺牲时间复杂度的情况下,极大优化空间使用,尤其适用于对空间有严格限制的场景(如嵌入式系统)。