二叉树的遍历模版(递归,迭代)

本贴最后更新于 1664 天前,其中的信息可能已经斗转星移

image.png

图片来自 leetcode

  • 深度优先遍历(dfs)
    • 前序遍历
    • 中序遍历
    • 后序遍历
  • 广度优先遍历(bfs)
type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

递归

递归版本,代码比较简单,只需改变 append 数据的位置即可。

前序遍历

func preorderTraversal(root *TreeNode) []int {
	var ret []int
	helper(root, &ret)
	return ret
}

func helper(root *TreeNode, data *[]int) {
	if root == nil {
		return
	}
	*data = append(*data, root.Val)
	helper(root.Left, data)
	helper(root.Right, data)
}

中序遍历

func inorderTraversal(root *TreeNode) []int {
	var ret []int
	helper(root, &ret)
	return ret
}

func helper(root *TreeNode, data *[]int) {
	if root == nil {
		return
	}
	helper(root.Left, data)
	*data = append(*data, root.Val)
	helper(root.Right, data)
}

后序遍历

func postorderTraversal(root *TreeNode) []int {
	var ret []int
	helperPostOrder(root, &ret)
	return ret
}

func helperPostOrder(root *TreeNode, data *[]int) {
	if root == nil {
		return
	}
	helperPostOrder(root.Left, data)
	helperPostOrder(root.Right, data)
	*data = append(*data, root.Val)
}

迭代

迭代版本,稍微复杂,需要模拟函数调用栈,需要使用 stack,只需要改变压栈的位置即可,代码模版性较好,便于记忆。

在文末附录有基于 golang 标准库的 list 实现的 stack 。

前序遍历

func preorderTraversal(root *TreeNode) []int {
	if root == nil {
		return nil
	}

	var ret []int
	s := stack.New()
	s.Push(root)

	for s.Len() > 0 {
		c := s.Pop()

		if c != nil {
			node := c.(*TreeNode)
			if node.Right != nil { //右节点先压栈,最后处理
				s.Push(node.Right)
			}
			if node.Left != nil {
				s.Push(node.Left)
			}

			s.Push(node) //当前节点重新压栈(留着以后处理),因为先序遍历所以最后压栈
			s.Push(nil)  //在当前节点之前加入一个空节点表示已经访问过了
		} else { // 当前 c == nil , 说明这个节点已经访问过了
			node := s.Pop().(*TreeNode) // node 是上面 s.Push(node) 中的那个 node
			ret = append(ret, node.Val)
		}
	}

	return ret
}

中序遍历

func inorderTraversal(root *TreeNode) []int {
	if root == nil {
		return nil
	}

	var ret []int
	s := stack.New()
	s.Push(root)

	for s.Len() > 0 {
		c := s.Pop()

		if c != nil {
			node := c.(*TreeNode)

			if node.Right != nil {
				s.Push(node.Right) //右节点先压栈,最后处理
			}
			s.Push(node)
			s.Push(nil)
			if node.Left != nil {
				s.Push(node.Left)
			}
		} else {
			node := s.Pop().(*TreeNode)
			ret = append(ret, node.Val)
		}
	}

	return ret
}

后序遍历

func postorderTraversal(root *TreeNode) []int {
	if root == nil {
		return nil
	}

	var ret []int
	s := stack.New()
	s.Push(root)

	for s.Len() > 0 {
		c := s.Pop()

		if c != nil {
			node := c.(*TreeNode)

			s.Push(node)
			s.Push(nil)

			if node.Right != nil {
				s.Push(node.Right)
			}
			if node.Left != nil {
				s.Push(node.Left)
			}
		} else {
			node := s.Pop().(*TreeNode)
			ret = append(ret, node.Val)
		}
	}

	return ret
}

附录

stack 实现

package stack

import "container/list"

type Stack interface {
	Push(v interface{})
	Pop() interface{}
	Len() int
}

type stack struct {
	list *list.List
}

func New() Stack {
	return &stack{
		list: list.New(),
	}
}
func (s *stack) Push(v interface{}) {
	s.list.PushBack(v)
}

func (s *stack) Pop() interface{} {
	v := s.list.Back()
	if v == nil {
		return nil
	}

	return s.list.Remove(v)
}

func (s *stack) Len() int {
	return s.list.Len()
}
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...