代码随想录算法训练营第十四天(py)| 二叉树 | 递归遍历、迭代遍历、统一迭代

1 理论基础

1.1 二叉树的种类

满二叉树

只有度为0和2的节点,且度为0的节点在同一层。
深度为k,有2^k-1个节点
满二叉树

完全二叉树

除了最底层可能没填满,其余每层节点数都达到最大。并且最底层节点全部集中在左边。
在这里插入图片描述

二叉搜索树

是一个有数值的有序树。左子树的所有节点均小于根节点,右子树的所有节点均大于根节点。
在这里插入图片描述
大的放右边,小的放左边。

平衡二叉搜索树。

若非空,则左右两个子树的高度差不超过1,并且两个子树都是平衡二叉树
在这里插入图片描述

1.2 二叉树的存储

链式存储

用指针。一般用这个
在这里插入图片描述

顺序存储

用数组
在这里插入图片描述
若父节点的数组下标为i,则左子节点下标为2i+1,右子节点下标为2i+2。

1.3 二叉树的遍历方式

深度优先遍历:往深里走,直到碰到叶子节点。
-前序遍历:中左右
-中序遍历:左中右
-后序遍历:左右中
广度优先遍历:一层一层走
在这里插入图片描述
python下的树定义:

class TreeNode:
	def __init__(self, val, left=None, right=None):
		self.val = val # 值
		self.left = left # 左指针
		self.right = right # 右指针

2 递归遍历

每次写递归要按照以下三要素来写:

  1. 确定递归函数的参数和返回值。
  2. 确定终止条件
  3. 确定单层递归的逻辑

2.1 前序递归(中左右)

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
    	res = []
    	def dfs(node):
    		if node is None:
    			return
    		res.append(node.val)
    		dfs(node.left)
    		dfs(node.right)
    	dfs(root)
    	return res

2.1 中序递归(左中右)

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
    	res = []
    	def dfs(node):
    		if node is None:
    			return
    		dfs(node.left)
    		res.append(node.val)
    		dfs(node.right)
    	dfs(root)
    	return res

2.3 后序递归(左右中)

class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
    	res = []
    	def dfs(node):
    		if node is None:
    			return
    		dfs(node.left)
    		dfs(node.right)
		    res.append(node.val)
	    dfs(root)
    	return res

3 迭代遍历

需要创建一个数组res用于保存结果,和一个栈stack用于保存当前节点。迭代中有两个操作:

  1. 处理当前节点:将元素放入res中
  2. 遍历节点

3.1 前序迭代遍历(中左右)

先将根节点压栈,然后右子节点压栈,然后左子节点压栈
注意:这里和中左右的顺序是相反的!因为这么做出栈的时候才是正确的顺序

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
    	stack = [root]
    	res = []
    	if root == None:
    		return res
    	while stack: # 当栈非空时
    		node = stack.pop()
    		res.append(node.val) # 中结点先处理
    		if node.right: # 右孩子先入栈
    			stack.append(node.right)
    		if node.left:  # 左孩子后入栈
    			stack.append(node.left)
    	return res

3.2 中序迭代遍历(左中右)

中序迭代遍历的代码不与前序的通用,因为处理顺序和访问顺序不一样。

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
    	res = []
    	stack = [] # 不能提前将root放入stack
    	cur = root # 当前节点
  	    if root == None:
    		return res
    	while cur or stack: # 当当前节点和栈有一个非空时
    		if cur != None:
    			stack.append(cur)
    			cur = cur.left  # 先一直靠左深入
    		else: # 当左边走到头了,处理栈顶节点
    			cur = stack.pop()
    			res.append(cur.val) # 中
    			cur = cur.right # 右
    	return res
    	

3.3 后序迭代遍历(左右中)

调整前序遍历的顺序即可,将res反转。
注意,反转前res的顺序为中右左,因此入栈的顺序应该左孩子先入栈,右孩子后入栈。

class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
    	res = []
    	stack = [root]
		if root == None:
    		return res
    	while stack:
    		node = stack.pop()
    		res.append(node.val)
    		if node.left:
    			stack.append(node.left)# 左孩子先入栈
    		if node.right:
    			stack.append(node.right)# 右孩子后入栈
    	return res[::-1] #反转

4 统一迭代

其实针对三种遍历方式,使用迭代法是可以写出统一风格的代码。
就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。要处理的节点放入栈之后,紧接着放入一个空指针作为标记。

4.1 前序遍历(中左右)

class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
    	res = []
    	stack = [root]
    	if root == None:
    		return res
    	while stack:
    		if node != None:
    			if node.right:
    				stack.append(node.right)
    			if node.left:
    				stack.append(node.left)
    			stack.append(node) # 把访问的节点和要处理的节点都入栈
    			stack.append(None) # 并且在要处理的节点之后添加一个空值
    		else:
    			node = stack.pop()
    			res.append(node.val)
    	return res

4.2 中序遍历(左中右)

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
    	res = []
    	stack = [root]
    	if root == None:
    		return res
    	while stack:
    		node = stack.pop()
    		if node != None:
    			if node.right:
    				stack.append(node.right)
    			stack.append(node)
    			stack.append(None)
    			if node.left:
    				stack.append(node.left)
    		else:
    			node = stack.pop()
    			res.append(node.val)
    	return res

4.3 后序遍历(左右中)

class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
    	res = []
    	stack = [root]
    	if root == None:
    		return res
    	while stack:
    		node = stack.pop()
    		if node != None:
    			stack.append(node)
    			stack.append(None)
    			if node.right != None:
    				stack.append(node.right)
    			if node.left != None:
    				stack.append(node.left)
    		else:
    			node = stack.pop()
    			res.append(node.val)
    	return res
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值