145 二叉树的后序遍历-简单
题目:
给你一棵二叉树的根节点 root
,返回其节点值的 后序遍历 。
分析:
算法1:递归
// 递归
func postorderTraversal(root *TreeNode) []int {
if root == nil {
return []int{}
}
res := make([]int, 0, 16)
if root.Left != nil {
res = append(res, postorderTraversal(root.Left)...)
}
if root.Right != nil {
res = append(res, postorderTraversal(root.Right)...)
}
res = append(res, root.Val)
return res
}
算法2:迭代【推荐该算法】
迭代遍历的时候依然需要 stack 结构来保存已经遍历过的节点;同时借助 pre 指针保存上次出栈的节点,用于判断当前节点是否同时具有左右子树,还是只有单个子树。
先将根节点入栈,循环遍历栈是否为空
出栈,取出当前节点
如果当前节点没有左右子树,则为叶子节点,直接加入结果集
其次判断上次出栈的节点是否是当前节点的左右子树,如果是,表明当前节点的子树已经处理完毕,也需要加入结果集【这里依赖的是左右子树的入栈,因为在栈中左右子树不具备前继关系,至于根节点具备】
依次检查当前节点的右子树,左子树,重复1,2
// 迭代版
// date 2023/10/18
// left->right-root
func postorderTraversal(root *TreeNode) []int {
if root == nil {return nil}
res := make([]int, 0)
stack := make([]*TreeNode, 0)
stack = append(stack, root)
var pre, cur *TreeNode // 记录前驱节点和当前节点
for len(stack) != 0 {
// 出栈 当前结点
cur = stack[len(stack)-1]
// 如果当前结点为叶子结点,则直接加入结果集
// 如果当前结点不是叶子结点,但是上次遍历结点为当前结点的左右子树时(说明当前结点只有单个子树,且子树已经处理完毕),也加入结果集
if cur.Left == nil && cur.Right == nil || pre != nil && (pre == cur.Left || pre == cur.Right) {
res = append(res, cur.Val)
// 出栈,继续检查
stack = stack[:len(stack)-1]
pre = cur
} else {
// 因为在出栈的时候检查结点,并追加到结果中
// 所以,先入栈右子树,后入栈左子树
if cur.Right != nil {
stack = append(stack, cur.Right)
}
if cur.Left != nil {
stack = append(stack, cur.Left)
}
}
}
return res
}
最后更新于