94. 二叉树的中序遍历

244 阅读1分钟

leetcode原题链接

给定一个二叉树,返回它的中序遍历。

示例:


输入: [1,null,2,3]
   1
    \
     2
    /
   3

输出: [1,3,2]

方法一

递归

func inorderTraversal1(_ root: TreeNode?) -> [Int] {
        guard let root = root else { return [] }
        
        var seq: [Int] = []
        seq += inorderTraversal1(root.left)
        seq.append(root.val)
        seq += inorderTraversal1(root.right)
        return seq
    }

方法二

迭代

func inorderTraversal(_ root: TreeNode?) -> [Int] {
        var stack: [TreeNode] = []
        var result: [Int] = []
        var node: TreeNode? = root
        
        while node != nil || !stack.isEmpty {
            while node != nil {
                stack.append(node!)
                node = node!.left
            }
            
            node = stack.popLast()
            result.append(node!.val)
            node = node?.right
        }
        
        return result
    }

方法三

Morris算法

树的某些节点的left或right为空,我们可以利用这些空间来存储遍历过程中的前驱和后继,而不需要使用额外的栈。在 Morris 算法中,使用节点的right位置来储存它的后继,这样当我们访问完这个节点之后就可以进行通过right进入后继节点。(前驱和后继是以最终的输出序列为参照的)

对于一个节点,它的左子树的最右节点就是它的前驱节点。

为了确保总是有路可回,对于每一次迭代,在进行移动之前都先要查找当前节点的前驱节点,然后建立线索,使前驱节点的右孩子指向当前节点。

inorderTraversal(_ root: TreeNode?) -> [Int] {
        var current, prev: TreeNode?
        var res: [Int] = []
        current = root
        
        while current != nil {
            if current!.left == nil {
                res += [current!.val]
                current = current!.right
            } else {
                prev = current!.left
                while prev!.right != nil && prev!.right !== current {
                    prev = prev!.right
                }
                
                if prev!.right === current {
                    prev!.right = nil
                    res += [current!.val]
                    current = current!.right
                } else {
                    prev!.right = current
                    current = current!.left
                }
            }
        }
        return res
    }