给定一个二叉树,返回它的中序遍历。
示例:
输入: [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
}