今日任务:
资料来源:
满二叉树:如果一棵二叉树的所有节点的度要么是0要么是2,并且度为0的节点在同一层上,那么它就是一棵满二叉树。
完全二叉树:在完全二叉树中,除了最底层以外,其余每层节点数量都达到最大值,并且最下面一层的节点都集中在该层的最左边的若干位置。若最底层为第h层,则该层的节点数不超过到这个范围。
二叉搜索树:二叉搜索树是一个有序树,它符合以下条件:
平衡二叉搜索树:AVL树,它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是平衡二叉树。
二叉树的遍历方式:深度优先搜索(DFS,可以前序中序后序,使用栈)、广度优先搜索(BFS,可以层序,使用队列)、前序(中左右,可以递归可以迭代)、中序(左中右,可以递归可以迭代)、后序(左右中,可以递归可以迭代)、层序(可以迭代)。
二叉树的定义
pythonclass TreeNode:
def __init__(self, val: int, left: TreeNode = None, right: TreeNode = None):
self.val = val
self.left = left
self.right = right
递归的三要素:
递归函数的参数和返回值
终止条件
单层递归的逻辑
以前序遍历为例:
递归函数的参数和返回值:遍历不需要处理数据什么的,所以只需要传入要遍历的节点和存放遍历结果的数据即可。
终止条件:如果当前要遍历的节点是空,遍历就要结束了,这就是终止条件。
单层递归的逻辑:前序遍历是中左右,那就是先遍历中间的,然后调用函数遍历左子树的,最后是右子树的。
根据这三个条件,前序遍历的代码就是这样:
python# 二叉树的前序遍历 递归写法
from typing import Optional, List
# 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]:
return self.traversal(root, []) # 进入递归
def traversal(self, node: Optional[TreeNode], result: List[int]) -> List[int]: # 参数和返回值
if node is None: # 终止条件
return result
else:
# 单层递归的逻辑
result.append(node.val)
self.traversal(node.left, result)
self.traversal(node.right, result)
return result
举一反三,中序和后序的代码也是差不多:
python# 二叉树的中序遍历 递归写法
from typing import Optional, List
# 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 inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
return self.traversal(root, [])
def traversal(self, node: TreeNode, result: List[int]) -> List[int]:
if node is not None:
self.traversal(node.left, result)
result.append(node.val)
self.traversal(node.right, result)
return result
python# 二叉树的后序遍历 递归写法
from typing import Optional, List
# 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 postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
return self.traversal(root, [])
def traversal(self, node: TreeNode, result: List[int]) -> List[int]:
if node is None:
return result
else:
self.traversal(node.left, result)
self.traversal(node.right, result)
result.append(node.val)
return result
之前的前序,中序和后序遍历都用的递归来写的,而栈又是递归所用的函数栈的底层,那么栈也能替代递归,使得二叉树的遍历不使用递归方式完成。
前序遍历:要先处理的是根节点,之后是左节点,最后是右节点。在栈中也是先弹出当前节点进行处理,然后加入它的左节点和右节点,下次循环再出栈一个元素。
python# 二叉树的前序遍历 迭代写法
from collections import deque
from typing import Optional, List
# 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]:
stack = deque()
if root is None:
return []
result = []
node = root
stack.append(node)
while node is not None and len(stack) != 0:
node = stack.pop()
result.append(node.val)
if node.right is not None: # 栈是先进后出 所以先进右节点
stack.append(node.right)
if node.left is not None:
stack.append(node.left)
return result
中序遍历:这次维护的栈,必须保证栈顶是目前子树中最“左”的节点,如果已经指到叶子节点了,之后指向空了,就可以从栈中取出元素,处理并且指向右节点了。
python# 二叉树的中序遍历 迭代写法
from collections import deque
from typing import Optional, List
# 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 inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if root is None:
return []
stack = deque()
result = []
node = root
while node is not None or len(stack) != 0:
if node is not None: # 这一部分的目的是先让栈顶存着目前子树最“左”的节点
stack.append(node)
node = node.left
else:
node = stack.pop() # 到这一步可以确定没有再“左”的节点了 从栈中弹出并且处理之前的节点
result.append(node.val)
node = node.right
return result
后序遍历:由于后序遍历的顺序和前序完全相反,所以直接先前序调整一下顺序,然后出了结果反转一下即可。
python# 二叉树的后序遍历 迭代写法
from collections import deque
from typing import Optional, List
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if root is None:
return []
stack = deque()
result = []
node = root
stack.append(node)
while len(stack) != 0:
node = stack.pop()
result.append(node.val)
if node.left is not None:
stack.append(node.left)
if node.right is not None:
stack.append(node.right)
result.reverse()
return result
在之前的迭代法中,前、后序和中序的写法有截然不同的区别。这是因为前、后序要处理加入结果数组的节点,和每次循环弹出的节点是一致的,而中序不是一致的。而不一致的解决方法,可以通过在栈中加入标记来解决,因此就有了统一写法的迭代法(也称标记法)。
这种统一写法的迭代法不是很好想,但是优势前中后序改变很容易,也很好记。也需要会写。
python# 二叉树的前序遍历 统一迭代写法
from collections import deque
from typing import Optional, List
# 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 root is None:
return []
stack = deque()
result = []
node = root
stack.append(node)
while len(stack) != 0:
node = stack.pop()
if node is not None:
if node.right is not None:
stack.append(node.right)
if node.left is not None:
stack.append(node.left)
stack.append(node)
stack.append(None) # 标记在这里 这个标记的含义是它前面的节点已经被处理 不再需要向下找子节点了
else:
node = stack.pop()
result.append(node.val) # 因为有标记所以直接加入值
return result
python# 二叉树的后序遍历 统一迭代写法
from collections import deque
from typing import Optional, List
# 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 postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if root is None:
return []
stack = deque()
result = []
node = root
stack.append(node)
while len(stack) != 0:
node = stack.pop()
if node is None:
node = stack.pop()
result.append(node.val)
else:
# 相比前序 只有下面这6行代码有顺序变化
stack.append(node)
stack.append(None)
if node.right is not None:
stack.append(node.right)
if node.left is not None:
stack.append(node.left)
return result
python# 二叉树的中序遍历 统一迭代写法
from collections import deque
from typing import Optional, List
# 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 inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if root is None:
return []
stack = deque()
result = []
node = root
stack.append(node)
while len(stack) != 0:
node = stack.pop()
if node is None:
node = stack.pop()
result.append(node.val)
else:
# 同理 只有下面有顺序变化
if node.right is not None:
stack.append(node.right)
stack.append(node)
stack.append(None)
if node.left is not None:
stack.append(node.left)
return result
本文作者:御坂19327号
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!