二叉树
二叉树的定义
class TreeNode(object):
def __init__(self,value,left=None,right=None):
self.val=val
self.left=left
self.right=right
递归遍历 和迭代遍历
递归的终止条件!
深度优先遍历
前序遍历 根左右
递归
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
res=[]
def preorder(root):
if root is None: return
res.append(root.val)
preorder(root.left)
preorder(root.right)
preorder(root)
return res
迭代
因为顺序为根左右,所以需要借助栈,栈是先入后出的,所以,先读取cur.val,然后往里放他的子节点,先放right再放left
def preorderTraversal(self, root):
# 根结点为空则返回空列表
if root is None:return []
stack=[root]
res=[]
while stack:
curnode=stack.pop()
res.append(curnode.val)
if curnode.right:
stack.append(curnode.right)
if curnode.left:
stack.append(curnode.left)
return res
中序遍历 左根右
递归
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
res=[]
def inorder(root):
if root is None:return
inorder(root.left)
res.append(root.val)
inorder(root.right)
inorder(root)
return res
迭代
因为要先读最左边的,所以要一直向左压栈,压到没有后,栈弹出,读取,然后cur=cur.right
def inorderTraversal(self, root):
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
后序遍历 左右根
递归
def postorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
res=[]
def postorder(root):
if root is None:return
postorder(root.left)
postorder(root.right)
res.append(root.val)
postorder(root)
return res
迭代
方法一:把前序遍历的顺序调整为根右左,然后翻转列表
def postorderTraversal(self, root):
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(object):
def postorderTraversal(self, root):
if not root:
return []
stack = []
result = []
cur=root
pre=root
while cur:
while cur.left:
#print('append',cur.val)
node = stack.append(cur)
cur=cur.left
#print('cur',cur.val)
while cur and (cur.right is None or cur.right ==pre):
#当前结点非空且右孩子已经被访问过了
#print('res',cur.val)
result.append(cur.val)
#print('res2',result)
pre=cur
if not stack :
#print('yes')
return result
cur=stack.pop()
stack.append(cur)
#print('a',cur.val)
cur=cur.right
#print('result',result)
return result
广度优先遍历(层次遍历)
102. 二叉树的层序遍历
迭代用队列
递归
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
res = []
def helper(root, depth):
if not root: return []
if len(res) == depth: res.append([]) # start the current depth
res[depth].append(root.val) # fulfil the current depth
if root.left: helper(root.left, depth + 1) # process child nodes for the next depth
if root.right: helper(root.right, depth + 1)
helper(root, 0)
return res
迭代
class Solution(object):
def levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
results = []
if not root:
return results
from collections import deque
que = deque([root])
while que:
size = len(que)
result = []
for _ in range(size):
cur = que.popleft()
result.append(cur.val)
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
results.append(result)
return results
二叉树的重建
根据前序和中序遍历重建二叉树
- 根据前序序列的第一个元素建立根结点;
- 在中序序列中找到该元素,确定根结点的左右子树的中序序列;
- 在前序序列中确定左右子树的前序序列(根据中序中分割的左右子树的长度)
- 由左子树的前序序列和中序序列建立左子树;
- 由右子树的前序序列和中序序列建立右子树。
用递归实现
细节:用哈希表存储步骤2中中序序列个元素值与下标的关系,避免频繁查找浪费的时间
class Solution(object):
def buildTree(self, preorder, inorder):
self.index={element:i for i,element in enumerate(inorder)}
def build(preorder, inorder,id_in):
#1、递归结束条件
if not preorder: return None
#2、从前序找根节点
val=preorder[0]
root=TreeNode(val)
#3、找中序根节点位置
idx=self.index[val]-id_in
#4、分割中序
in_left=inorder[0:idx]
in_right=inorder[idx+1:]
#5、分割前序
pre_left=preorder[1:1+len(in_left)]
pre_right=preorder[1+len(in_left):]
root.left=build(pre_left,in_left,id_in)
root.right=build(pre_right,in_right,id_in+idx+1)
return root
return build(preorder, inorder,0)
根据中序加后序遍历重建二叉树
构造该二叉树的过程如下:
- 根据后序序列的最后一个元素建立根结点;
- 在中序序列中找到该元素,确定根结点的左右子树的中序序列;
- 在后序序列中确定左右子树的后序序列;
- 由左子树的后序序列和中序序列建立左子树;
- 由右子树的后序序列和中序序列建立右子树。
class Solution(object):
def buildTree(self, inorder, postorder):
self.index = {element: i for i, element in enumerate(inorder)}
def build(inorder, postorder,id_in):
#1、递归结束条件 特殊情况讨论: 树为空. (递归终止条件)
if not postorder:return None
#2、从后序找当前根 后序遍历的最后一个就是当前的中间节点.
val=postorder[-1]
root=TreeNode(val)
#3、找中序的根 找切割点.
#print(val,inorder)
idx=self.index[val]-id_in
#4、切割 切割inorder数组. 得到inorder数组的左,右半边
in_left=inorder[:idx]
in_right=inorder[idx+1:]
#5、切割 切割postorder数组. 得到postorder数组的左,右半边.
#⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
po_left=postorder[:len(in_left)]
po_right=postorder[len(in_left):len(postorder)-1]
#6、递归重建
root.left=build(in_left,po_left,id_in)
root.right=build(in_right,po_right,id_in+idx+1)
return root
return build(inorder, postorder,0)
前序加后序不能重建二叉树
前序和后序在本质上都是将父节点与子结点进行分离,但并没有指明左子树和右子树的能力,因此得到这两个序列只能明确父子关系,而不能确定一个二叉树。