二叉树
前序遍历
先访问根节点,再前序遍历左子树,再前序遍历右子树
中序遍历
先中序左子树,在访问根节点,再中序遍历右子树
后序遍历
先后序遍历左子树,再后序遍历右子树,再访问跟节点
解法
递归
三种遍历方式递归代码基本一致,根据遍历顺序调整结果保存与递归代码顺序即可
迭代
采用压栈的方式,核心代码基本也是一致的,只是压栈和结果保存的时机稍微一点区别
代码
// 递归模板
func recursionTraversal(root *TreeNode) (res []int) {
if root == nil{
return nil
}
var recursion func(root *TreeNode)
recursion = func(root *TreeNode){
if root == nil{
return
}
// 前序遍历
res = append(res,root.Val)
postorder(root.Left)
postorder(root.Right)
// 中序遍历
postorder(root.Left)
res = append(res,root.Val)
postorder(root.Right)
// 后序遍历
postorder(root.Left)
postorder(root.Right)
res = append(res,root.Val)
}
recursion(root)
return
}
// 前序迭代遍历
func preorderTraversal(root *TreeNode) []int{
if root == nil {
return nil
}
// 最终返回结果
result := make([]int,0)
// 堆栈存储中间节点
stack := make([]*TreeNode,0)
// 当二叉树左右遍历节点都为空,堆栈无节点退出循环
for root != nil || len(stack) != 0 {
// 循环 保存根节点 将节点保存栈中 继续读取左节点
for root != nil {
result = append(result,root.Val)
stack = append(stack,root)
root = root.Left
}
// 上方循环无左节点了 执行stack pop操作 赋值 root 右节点继续遍历
node := stack[len(stack)-1]
stack = stack[:len(stack)-1]
root = node.Right
}
return result
}
// 中序迭代遍历
func inorderTraversal(root *TreeNode) []int {
result := make([]int,0)
if root == nil{
return result
}
stack := make([]*TreeNode,0)
for len(stack) > 0 || root != nil {
// 存储访问元素,一直向左
for root != nil{
stack = append(stack,root)
root = root.Left
}
val := stack[len(stack)-1]
stack = stack[:len(stack)-1]
result = append(result,val.Val)
root = val.Right
}
return result
}
// 后序迭代遍历
func postorderTraversal(root *TreeNode) []int {
if root == nil{
return nil
}
result := make([]int,0)
stack := make([]*TreeNode,0)
var lastVisit *TreeNode
for root != nil || len(stack) != 0 {
for root != nil{
stack = append(stack,root)
root = root.Left
}
node := stack[len(stack)-1]
// 确保不存在右节点或右节点已经弹出后弹出根元素
if node.Right == nil || node.Right == lastVisit{
stack = stack[:len(stack)-1]
result = append(result,node.Val)
// 标识节点已弹出
lastVisit = node
}else{
root = node.Right
}
}
return result
}