二叉树理论
解题过程中二叉树有两种主要的形式:满二叉树和完全二叉树
满二叉树
满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
深度 K, 2^k -1个节点
完全二叉树
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点。
二叉搜索树
二叉搜索树是有数值的了,二叉搜索树是一个有序树。
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树
平衡二叉树
它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
存储方式
-
链式存储
-
顺序存储—数组
用数组来存储二叉树如何遍历的呢?
如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。
遍历方式
深度优先—一直走,发现没路了就回头
广度优先—一层一层走
- 深度优先遍历
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法) - 广度优先遍历
- 层次遍历(迭代法)
递归实现深度优先
队列实现广度优先
class TreeNode:
def __init__(self, val, 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]
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 preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
def pre_bf(root):
if root is None: return
result.append(root.val)
pre_bf(root.left)
pre_bf(root.right)
pre_bf(root)
return result
中序遍历
左根右,入栈右根左
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = [] # 不能提前将root结点加入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 inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res =[]
def mid_bf(node):
if node is None:return
mid_bf(node.left)
res.append(node.val)
mid_bf(node.right)
mid_bf(root)
return res
后序遍历
迭代:左右根–栈右左根
递归
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res =[]
def df_bf(node):
if node is None:return
df_bf(node.left)
df_bf(node.right)
res.append(node.val)
df_bf(root)
return res
总结
-
递归—寻找相同子模块
1、寻找做相同的东西的子模块
2、子模块的范围也就是具体参数是变化的,注意参数变化 -
迭代–实现递归的具体方法