多叉树的递归/层序遍历
一句话总结
多叉树结构就是二叉树结构的延伸,二叉树是特殊的多叉树。森林是指多个多叉树的集合。
多叉树的遍历就是二叉树遍历的延伸。
二叉树的节点长这样,每个节点有两个子节点:
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
多叉树的节点长这样,每个节点有任意个子节点:
type Node struct {
val int
children []*Node
}
就这点区别,其他没了。
森林
这里介绍一下「森林」这个名词,后面讲到 [UnionFind] 并查集算法 时,会用到这个概念。
顾名思义,森林就是多个多叉树的集合(一棵多叉树是一个特殊的森林),用代码表示就是多个多叉树的根节点列表,类似这样:
List<TreeNode> forest;
只需对每个根节点分别进行 DFS/BFS 遍历,即可遍历森林的所有节点。
在并查集算法中,我们会同时持有多棵多叉树的根节点,那么这些根节点的集合就是一个森林。
接下来说下多叉树的遍历,和二叉树一样,也就递归遍历(DFS)和层序遍历(BFS)两种。
递归遍历(DFS)
对比二叉树的遍历框架看多叉树的遍历框架吧:
// 二叉树的遍历框架
func traverse(root *TreeNode) {
if root == nil {
return
}
// 前序位置
traverse(root.Left)
// 中序位置
traverse(root.Right)
// 后序位置
}
// N 叉树的遍历框架
func traverseNary(root *Node) {
if root == nil {
return
}
// 前序位置
for _, child := range root.Children {
traverseNary(child)
}
// 后序位置
}
唯一的区别是,多叉树没有了中序位置,因为可能有多个节点嘛,所谓的中序位置也就没什么意义了。
层序遍历(BFS)
多叉树的层序遍历和二叉树的层序遍历一样,都是用队列来实现,无非就是把二叉树的左右子节点换成了多叉树的所有子节点。所以多叉树的层序遍历也有三种写法,下面一一列举。
写法一
第一种层序遍历写法,无法记录节点深度:
func levelOrderTraverse(root *Node) {
if root == nil {
return
}
q := []*Node{}
q = append(q, root)
for len(q) > 0 {
cur := q[0]
q = q[1:]
// 访问 cur 节点
fmt.Println(cur.Val)
// 把 cur 的所有子节点加入队列
for _, child := range cur.Children {
q = append(q, child)
}
}
}
写法二
第二种层序遍历写法,能够记录节点深度:
func levelOrderTraverse(root *Node) {
if root == nil {
return
}
q := []*Node{root}
// 记录当前遍历到的层数(根节点视为第 1 层)
depth := 1
for len(q) > 0 {
sz := len(q)
for i := 0; i < sz; i++ {
cur := q[0]
q = q[1:]
// 访问 cur 节点,同时知道它所在的层数
fmt.Printf("depth = %d, val = %d\n", depth, cur.val)
for _, child := range cur.children {
q = append(q, child)
}
}
depth++
}
}
写法三
第三种能够适配不同权重边的写法:
// 多叉树的层序遍历
// 每个节点自行维护 State 类,记录深度等信息
type State struct {
node *Node
depth int
}
func levelOrderTraverse(root *Node) {
if root == nil {
return
}
q := []State{}
// 记录当前遍历到的层数(根节点视为第 1 层)
q = append(q, State{root, 1})
for len(q) > 0 {
state := q[0]
q = q[1:]
cur := state.node
depth := state.depth
// 访问 cur 节点,同时知道它所在的层数
fmt.Printf("depth = %d, val = %d\n", depth, cur.Val)
for _, child := range cur.Children {
q = append(q, State{child, depth + 1})
}
}
}
没啥好说的,有不明白的可以对照前文二叉树遍历的层序遍历代码和可视化面板。