这是树的第11篇算法,力扣链接。
给你二叉树的根节点
root
,返回它节点值的 前序 遍历。示例 1:
输入:root = [1,null,2,3] 输出:[1,2,3]
做了这么久的树问题,现在开始回忆三种遍历方法,这篇文章回忆的是前序遍历。
前序遍历 (Preorder Traversal)
在前序遍历中,节点的访问顺序如下:
- 访问根节点
- 遍历左子树
- 遍历右子树
前序遍历通常用于创建树的副本。当你访问节点之后立即复制节点,你可以通过前序遍历复制所有节点并创建一棵相同的树。
例子
假设有一棵二叉树如下:
A / \ B C / \ \ D E F
对这棵树进行不同的遍历会得到以下结果:
- 前序遍历:
A, B, D, E, C, F
。首先访问根节点(A),然后是左子树(B, D, E),最后是右子树(C, F)。
这里用迭代和递归一起回忆一下这个前序遍历的实现方法。
迭代思路是尽量选取左节点,当左节点没有的时候栈弹出选取右节点。
func preorderTraversal(root *TreeNode) []int {
var result []int
if root == nil {
return result
}
stack := []*TreeNode{root}
node := root
for len(stack) > 0 {
for node != nil {
result = append(result, node.Val)
stack = append(stack, node)
node = node.Left
}
node = stack[len(stack)-1].Right
stack = stack[:len(stack)-1]
}
return result
}
这是另一种写法,先把按照最左路径把右、左节点依次入栈。
func preorderTraversal(root *TreeNode) []int {
var result []int
if root == nil {
return result
}
stack := []*TreeNode{root}
node := root
for len(stack) > 0 {
node = stack[len(stack)-1]
stack = stack[:len(stack)-1]
result = append(result, node.Val)
if node.Right != nil {
stack = append(stack, node.Right)
}
if node.Left != nil {
stack = append(stack, node.Left)
}
}
return result
}
递归写法如下:
func preorderTraversal(root *TreeNode) []int {
var result []int
preorder(root, &result)
return result
}
func preorder(node *TreeNode, result *[]int) {
if node == nil {
return
}
*result = append(*result, node.Val)
preorder(node.Left, result)
preorder(node.Right, result)
}
还有指针的方法做的:
func PreorderTraversal(root *TreeNode) []int {
var result []int
current := root
for current != nil {
if current.Left == nil {
result = append(result, current.Val) // 访问当前节点
current = current.Right // 移动到右子树
} else {
// 寻找前驱节点
predecessor := current.Left
for predecessor.Right != nil && predecessor.Right != current {
predecessor = predecessor.Right
}
if predecessor.Right == nil {
result = append(result, current.Val) // 访问当前节点
// 将当前节点的右指针指向当前节点,建立一条回溯线索
predecessor.Right = current
current = current.Left // 移动到左子树
} else {
// 左子树已经访问完毕,恢复树的结构
predecessor.Right = nil
current = current.Right // 移动到右子树
}
}
}
return result
}