理论基础
二叉树的种类
-
满二叉树(深度为k,有(2^k - 1)个节点)
-
完全二叉树
除底部外其他节点都是满的,且底部从左至右连续。
-
二叉搜索树
· 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
**·**若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
**·**它的左、右子树也分别为二叉排序树。
-
平衡二叉搜索树
它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉树的存储方式
- 链式存储
- 线式存储(数组下标左孩子:I2+1;右孩子:I2+2)
二叉树的遍历
- 深度优先搜索:先往深走,遇到叶子节点再往回走
· 前序遍历:中左右(递归法、迭代法)
· 中序遍历:左中右(递归法、迭代法)
· 后序遍历:左右中(递归法、迭代法)
- 广度优先搜索:一层一层的去遍历
层序遍历(迭代法)
二叉树的定义
二叉树的定义 和链表是差不多的,相对于链表 ,二叉树的节点里多了一个指针, 有两个指针,指向左右孩子。
class TreeNode:
def __init__(self, val, left = None, right = None):
self.val = val
self.left = left
self.right = right
二叉树的递归遍历
- 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
- 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
- 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
res = []
# 前序遍历
def dfs(node):
if node is None:
return
res.append(node.val)
dfs(node.left)
dfs(node.right)
# 中序遍历
def dfs(node):
if node is None:
return
dfs(node.left)
res.append(node.val)
dfs(node.right)
# 后序遍历
def dfs(node):
if node is None:
return
dfs(node.left)
dfs(node.right)
res.append(node.val)
dfs(root)
return res
二叉树的迭代遍历
前序遍历
前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。(先加入右孩子再加入左孩子,保证出栈的时候才是中左右的顺序)
class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
res = []
stack = [root]
while stack:
tmp = stack.pop()
res.append(tmp.val) #中结点先处理
if tmp.right: # 右孩子先入栈
stack.append(tmp.right)
if tmp.left: # 左孩子后入栈
stack.append(tmp.left)
return res
后序遍历
先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中。
class Solution(object):
def postorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
res = []
stack = [root]
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]
中序遍历
中序遍历先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中)。代码实现的逻辑为先一路向左遍历直到出现左指针指向空(期间将遍历的每个左节点加入栈中),指向空时则将栈顶元素弹出,并加入result中(此时处理的是中节点)。然后判断当前节点的右节点,再一路向左遍历改右节点的左节点直到出现空节点,重复上述逻辑,直到栈为空。ps:循环的逻辑为栈和当前节点不同时为空。
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
stack = [] # 不能提前将root节点放入stack中
res = []
cur = root
while cur or stack:
# 先迭代访问最底层左子树节点
if cur:
stack.append(cur)
cur = cur.left
# 到达最左节点后处理栈顶节点
else:
cur = stack.pop()
res.append(cur.val)
# 取出栈顶元素右节点
cur = cur.right
return res