深度优先遍历中每个节点会被进入三次,
如果第一次进入就访问称为先序遍历,对于每个节点来说,会先访问它,再访问左子树,最后访问右子树
如果第二次进入才访问称为中序遍历,对于每个节点来说,会先访问左子树,再访问它,最后访问右子树
如果第三次进入才访问称为后序遍历,对于每个节点来说,会先访问左子树,再访问右子树,最后访问它
广度优先遍历每个节点只进入一次,
从图像上来看是从上到下、从左到右依次进入(访问)每个节点
class Node(object):
def __init__(self, item=None, lchild=None, rchild=None):
self.item = item
self.lchild = lchild
self.rchild = rchild
def build_tree1(preorder, inorder):
if len(preorder) == 0:
return None
tree = Node(preorder[0])
# 前序遍历的第一个元素为根节点,
# 中序遍历中,根节点的左边为左子树,右边为右子树
# 前序遍历序列中,左子树部分第一个出现的数为左子树根节点,同理右子树(这个信息目前不使用)
root_index_inorder = inorder.index(preorder[0])
# 已知左子树有root_index_inorder个元素
# 前序遍历序列中,根节点后取root_index_inorder个元素即为参与左子树构建的元素
tree.lchild = build_tree1(
preorder[1:root_index_inorder+1], inorder[:root_index_inorder])
# 前序遍历序列剩下的元素即为参与右子树构建的元素
tree.rchild = build_tree1(
preorder[root_index_inorder+1:], inorder[root_index_inorder+1:])
return tree
def build_tree2(inorder, postorder):
if len(postorder) == 0:
return None
tree = Node(postorder[-1])
# 后序遍历的最后一个元素为根节点,
# 中序遍历中,根节点的左边为左子树,右边为右子树
# 后序遍历序列中,左子树部分最后出现的数为左子树根节点,同理右子树(这个信息目前不使用)
root_index_inorder = inorder.index(postorder[-1])
# 已知左子树有root_index_inorder个元素
# 后序遍历序列中,前root_index_inorder个元素即为参与左子树构建的元素
tree.lchild = build_tree2(
inorder[:root_index_inorder], postorder[:root_index_inorder])
# 后序遍历序列中剩下的元素(不包括最后一个元素)即为参与右子树构建的元素
tree.rchild = build_tree2(
inorder[root_index_inorder+1:], postorder[root_index_inorder:-1])
return tree
def build_tree_bfs(arr):
root = Node(arr[0])
queue = [root]
arr.pop(0)
while arr and queue:
size = len(queue)
for _ in range(size):
cur = queue.pop(0)
if arr and not cur.lchild:
cur.lchild = Node(arr[0])
arr.pop(0)
queue.append(cur.lchild)
if arr and not cur.rchild:
cur.rchild = Node(arr[0])
arr.pop(0)
queue.append(cur.rchild)
return root
def bfs(root):
queue = []
queue.append(root)
while queue and queue[0]:
size = len(queue)
for i in range(size):
cur = queue.pop(0)
print(cur.item)
if cur.lchild:
queue.append(cur.lchild)
if cur.rchild:
queue.append(cur.rchild)
def dfs_preorder(root):
if not root:
return
print(root.item)
dfs_preorder(root.lchild)
dfs_preorder(root.rchild)
return
def dfs_preorder_stack(root):
if not root:
return
stack = []
cur = root
while stack or cur:
# 第一次进入某个节点cur,都是先访问,然后进入左节点
while cur:
print(cur.item)
stack.append(cur)
cur = cur.lchild
# 第二进入某个节点cur,由于先序遍历一定是已经访问过了,所以再进右节点
cur = stack.pop()
cur = cur.rchild
# 时间复杂度O(n)
# 空间复杂度O(logn)
def dfs_inorder(root):
if not root:
return
dfs_inorder(root.lchild)
print(root.item)
dfs_inorder(root.rchild)
return
# 时间复杂度O(n)
# 空间复杂度O(n)
def dfs_inorder_stack(root):
if not root:
return
stack = []
cur = root
while stack or cur:
# 第一次进入某个节点cur, 先进入其左节点
while cur:
stack.append(cur)
cur = cur.lchild
# 第二次进入某个几点cur, 由于是中序遍历,它的左子树应该全部访问过了
# 所以现在才访问cur, 然后进入它的右节点
cur = stack.pop()
print(cur.item)
cur = cur.rchild
def dfs_postorder(root):
if not root:
return
dfs_postorder(root.lchild)
dfs_postorder(root.rchild)
print(root.item)
return
# 按照根-右-左的顺序来访问,最后反向
def dfs_postorder_stack(root):
if not root:
return
stack = []
output = []
cur = root
while stack or cur:
# 第一次进入某个节点cur, 先访问,然后进入右节点
while cur:
output.append(cur.item)
stack.append(cur)
cur = cur.rchild
# 第二次进入某个节点cur, 由于是该节点已经被访问过,直接进入左节点
cur = stack.pop()
cur = cur.lchild
return output[::-1]
def get_maxdepth_bfs(root):
queue = []
queue.append(root)
max_depth = 0
while queue and queue[0]:
max_depth += 1
size = len(queue)
for i in range(size):
cur = queue.pop(0)
print(cur.item)
if cur.lchild:
queue.append(cur.lchild)
if cur.rchild:
queue.append(cur.rchild)
return max_depth
def get_maxdepth_dfs_postorder(root):
if not root:
return 0
left_depth = get_maxdepth_dfs_postorder(root.lchild)
right_depth = get_maxdepth_dfs_postorder(root.rchild)
max_depth = max(left_depth, right_depth) + 1
return max_depth
class GetMaxdepthDfsPreorder:
def _dfs_preorder(self, root, temp):
# temp是root的父节点的深度
if not root:
self.max_depth = max(temp, self.max_depth)
return
temp += 1
self._dfs_preorder(root.lchild, temp)
self._dfs_preorder(root.rchild, temp)
def _get_max_depth(self, root):
self.max_depth = -1
self._dfs_preorder(root, temp=0)
return self.max_depth
# 时间复杂度O(n)
# 空间复杂度O(logn)为栈的开销
# 每个节点只进入了一次
def is_symmetric(root):
def check(self, left, right):
if (not left) and (not right):
return True
elif (not left) or (not right):
return False
# 此时left, right全部是有值的
return (left.item == right.item) and check(left.lchild, right.rchild) \
and check(left.rchild, right.lchild)
return check(root, root)
# 由于递归的时候每个节点只进入了一次,将递归改成迭代依靠队列
# 时间复杂度O(n)
# 空间复杂度O(n)为队列的开销
def isSymmetric(root):
def check(left, right):
queue = []
queue.append(left)
queue.append(right)
# 改成迭代后,只有false才return, 最终运行完没有结束再return True
while queue:
left = queue.pop(0)
right = queue.pop(0)
# 枚举所有情况:
# 1:如果left right都是空,则当前是叶子节点
# 这里如果直接return整个程序就结束了,因此是continue继续判断其他节点
if (not left) and (not right):
continue
# 2: 如果left right只有一个为空,则一定不对称
elif (not left) or (not right):
return False
# 3: 如果left right都不为空,且值不等,则一定不对称
elif left.val != right.val:
return False
# 4: 如果left right都不为空,且值相同,
# 还要继续往下判断它的子节点的情况,所以并不是continue, 而是要把子节点入队列
else:
pass
queue.append(left.left)
queue.append(right.right)
queue.append(left.right)
queue.append(right.left)
return True
return check(root, root)