理论基础
满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
其节点数量是2^k - 1
完全二叉树:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
底部从左到右一定是连续的
满二叉树一定是完全二叉树
二叉搜索树:前面介绍的树,都没有数值的,而二叉搜索树是有数值的了,二叉搜索树是一个有序树。
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉排序树
平衡二叉搜索树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉树的存储方式:
顺序存储:
如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2
二叉树的遍历方式:
二叉树主要有两种遍历方式:
- 深度优先遍历:先往深走,遇到叶子节点再往回走。
- 广度优先遍历:一层一层的去遍历。
- 深度优先遍历
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法)
- 广度优先遍历
- 层次遍历(迭代法)
- 前序遍历:中左右
- 中序遍历:左中右
- 后序遍历:左右中
链式存储的二叉树节点的定义方式:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
递归遍历
144. 二叉树的前序遍历
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
145. 二叉树的后序遍历
# 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]:
result = []
def traversal(root: TreeNode):
if root == None:
return
#后序:左右中
traversal(root.left)
traversal(root.right)
result.append(root.val)
traversal(root)
return result
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 inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
def traversal(root: TreeNode):
if root == None:
return
#左中右
traversal(root.left)
result.append(root.val)
traversal(root.right)
traversal(root)
return result
迭代遍历
前序:
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 inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
#中序是左中右
#前序是中左右
if not root:
return []
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: Optional[TreeNode]) -> List[int]:
#前序 中左右
#后序 左右中 把前序的左右换成右入栈,变成中右左,然后整体reverse
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 preorderTraversal(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)
if node.left: #左
st.append(node.left)
st.append(node) #中
st.append(None)
else:
node = st.pop()
result.append(node.val)
return result
中序:
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
后序:
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
result = []
st = []
if root:
st.append(root)
while st:
node = st.pop()
if node != None:
st.append(node) #中
st.append(None)
if node.right: #右
st.append(node.right)
if node.left: #左
st.append(node.left)
else:
node = st.pop()
result.append(node.val)
return result
- 今日学习的文章链接
- 自己看到题目的第一想法
毫无头绪
- 看完代码随想录之后的想法
注意前中后的遍历顺序
迭代法里面的中序要加入指针
- 自己实现过程中遇到哪些困难
- 今日收获,记录一下自己的学习时长