算法记录 | Day13二叉树
二叉树的节点定义
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
-------------------------------------------------------------
LeetCode 144-二叉树的前序遍历
LeetCode 145-二叉树的后序遍历
LeetCode 94-二叉树的中序遍历
二叉树的前序、中序、后序遍历
题目链接:
递归遍历
解题思路
- 递归算法的三要素
- 确定递归函数的参数和返回值
- 确定终止条件
- 确定单层递归的逻辑
难点
-
递归思想
-
递归法
# 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: Optional[TreeNode]) -> List[int]:
# 保存结果
result = []
def traversal(root: TreeNode):
if root == None:
return
result.append(root.val) # 前序
traversal(root.left) # 左
traversal(root.right) # 右
traversal(root)
return result
# 后序遍历
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
def reversal(root):
if not root:
return
reversal(root.left)
reversal(root.right)
result.append(root.val)
reversal(root)
return result
# 中序遍历
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
def reversal(root):
if not root:
return
reversal(root.left)
result.append(root.val)
reversal(root.right)
reversal(root)
return result
写法二:
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 保存结果
if not root:
return []
return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
总结
- 递归的整个过程需要再写一个函数,我之前记忆的是写法二这种。
- 递归还是靠感觉。这个过程仿佛对我并不起什么作用。
迭代遍历
在[ 栈与队列:匹配问题都是栈的强项 ]中提到了,递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
解题思路
- 栈与队列的原理实现
- 整个过程其实和递归遍历的整个过程类似
# 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: Optional[TreeNode]) -> List[int]:
if not root:
return []
stack = [root]
# print(stack)
result = []
while stack:
node = stack.pop()
result.append(node.val)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
# 中序遍历(左中右)
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
stack = [] # 不能提前将root结点加入stack中
# print(stack)
result = []
cur = root
while cur or stack:
if cur:
stack.append(cur)
cur = cur.left
else:
cur = stack.pop()
result.append(cur.val)
cur = cur.right
return result
# 后序遍历(左右中)----刚好是前序反过来
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = [root]
result = []
while stack:
node = stack.pop()
# 中结点先处理
result.append(node.val)
# 左孩子先入栈
if node.left:
stack.append(node.left)
# 右孩子后入栈
if node.right:
stack.append(node.right)
# 将最终的数组翻转
return result[::-1]
难点
- 中序遍历与前序遍历和后序遍历是最不一样的
统一遍历
针对三种遍历方式,使用迭代法是可以写出统一风格的代码
解题思路
- 统一迭代法
- 中序遍历
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
result = []
st = []
if root:
st.append(root)
while st:
node = st.pop()
if node != None:
if node.right: #添加右节点(空节点不入栈)
st.append(node.right)
st.append(node) #添加中节点
st.append(None) #中节点访问过,但是还没有处理,加入空节点做为标记。
if node.left: #添加左节点(空节点不入栈)
st.append(node.left)
else: #只有遇到空节点的时候,才将下一个节点放进结果集
node = st.pop() #重新取出栈中元素
result.append(node.val) #加入到结果集
return result
难点
- 太多了,有点混乱了,不太好理解