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 递归遍历
每次写递归要按照以下三要素来写:
- 确定递归函数的参数和返回值。
- 确定终止条件
- 确定单层递归的逻辑
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用于保存当前节点。迭代中有两个操作:
- 处理当前节点:将元素放入res中
- 遍历节点
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



















