【golang】二叉树的遍历

本文使用golang实现二叉树的遍历,包含以下7种方法。

  • 深度优先遍历
    • 先序遍历
      • 递归法
      • 非递归法
    • 中序遍历
      • 递归法
      • 非递归法
    • 后序遍历
      • 递归法
      • 非递归法
  • 广度优先遍历

二叉树节点定义:

go 复制代码
type Node struct {
	Val   int
	Left  *Node
	Right *Node
}

深度优先遍历

先序遍历

定义

1) 访问根节点;

2) 先序遍历左子树;

3) 先序遍历右子树。

递归实现

go 复制代码
func preorder(root *Node, consume func(*Node)) {
	if root == nil {
		return
	}
	consume(root)
	preorder(root.Left, consume)
	preorder(root.Right, consume)
}

非递归实现

思路:使用一个栈实现

1)将根节点压入栈;

2)栈中弹出一个节点,访问该节点;

3)将该节点的右孩子、左孩子依次压入栈;

4)重复步骤2~3直至完成步骤3时栈为空。

栈实现:

go 复制代码
type Stack struct {
	values []*Node
}

func (s *Stack) Push(node *Node) {
	if s.values == nil {
		s.values = make([]*Node, 0)
	}
	s.values = append(s.values, node)
}

func (s *Stack) Pop() *Node {
	sl := len(s.values)
	if sl <= 0 {
		return nil
	}
	node := s.values[sl-1]
	s.values = s.values[:sl-1]
	return node
}

func (s *Stack) IsEmpty() bool {
	return len(s.values) == 0
}
go 复制代码
func preorder(root *Node, consume func(*Node)) {
	if root == nil {
		return
	}
	stack := Stack{}
	stack.Push(root)
	for node := stack.Pop(); node != nil; node = stack.Pop() {
		consume(node)
		if node.Right != nil {
			stack.Push(node.Right)
		}
		if node.Left != nil {
			stack.Push(node.Left)
		}
	}
}

中序遍历

定义

1) 中序遍历左子树;

2) 访问根节点;

3) 中序遍历右子树。

递归实现

go 复制代码
func inorder(root *Node, consume func(*Node)) {
	if root == nil {
		return
	}
	inorder(root.Left, consume)
	consume(root)
	inorder(root.Right, consume)
}

非递归实现

思路:使用一个栈实现

1) 将根节点及其所有直系左孩子压入栈(直系左孩子:其父节点也是左孩子);

2) 栈弹出一个节点,访问该节点;

3) 若弹出的节点有右孩子,则将右孩子视为根节点执行步骤1;

4) 重复步骤2~3,直至栈为空。

go 复制代码
func inorder(root *Node, consume func(*Node)) {
	if root == nil {
		return
	}
	stack := Stack{}
	pushAllLeft(root, &stack)
	for !stack.IsEmpty() {
		node := stack.Pop()
		consume(node)
		if node.Right != nil {
			pushAllLeft(node.Right, &stack)
		}
	}
}

func pushAllLeft(root *Node, stack *Stack) {
	for node := root; node != nil; node = node.Left {
		stack.Push(node)
	}
}

后序遍历

定义

1) 后序遍历左子树;

2) 后序遍历右子树;

3) 访问根节点。

递归实现

go 复制代码
func postorder(root *Node, consume func(*Node)) {
	if root == nil {
		return
	}
	postorder(root.Left, consume)
	postorder(root.Right, consume)
	consume(root)
}

非递归实现

思路:使用2个栈实现

1) 将根节点压入栈1;

2) 栈1弹出一个节点,将其左孩子、右孩子依次压入栈1;

3) 将步骤2弹出的节点压入栈2;

4) 重复步骤2~3,直至执行完步骤3时栈1为空;

5) 栈2弹出一个节点,并访问该节点;

6) 重复步骤5,直至栈2为空。

go 复制代码
func postorder(root *Node, consume func(*Node)) {
	if root == nil {
		return
	}
	stack1 := Stack{}
	stack2 := Stack{}
	stack1.Push(root)
	for !stack1.IsEmpty() {
		node := stack1.Pop()
		stack2.Push(node)
		if node.Left != nil {
			stack1.Push(node.Left)
		}
		if node.Right != nil {
			stack1.Push(node.Right)
		}
	}
	for !stack2.IsEmpty() {
		consume(stack2.Pop())
	}
}

广度优先遍历

定义 :按从上往下、从左往右的顺序来遍历

思路:使用一个队列实现

1) 将根节点加入队尾;

2) 从队列头取出一个节点,访问该节点;

3) 将该节点的左孩子、右孩子依次加入队尾;

4) 重复步骤2~3,直至执行完步骤3时队列为空。

go 复制代码
func widthorder(root *Node, consume func(*Node)) {
	if root == nil {
		return
	}
	queue := make([]*Node, 0)
	queue = append(queue, root)
	for len(queue) > 0 {
		node := queue[0]
		queue = queue[1:]
		consume(node)
		if node.Left != nil {
			queue = append(queue, node.Left)
		}
		if node.Right != nil {
			queue = append(queue, node.Right)
		}
	}
}
相关推荐
C++忠实粉丝39 分钟前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O1 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
代码雕刻家2 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
Kalika0-04 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
代码雕刻家4 小时前
课设实验-数据结构-单链表-文教文化用品品牌
c语言·开发语言·数据结构
怪我冷i5 小时前
使用vscode调试wails项目(golang桌面GUI)
vscode·golang
小字节,大梦想5 小时前
【C++】二叉搜索树
数据结构·c++
我是哈哈hh6 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
丶Darling.6 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo5206 小时前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法