前话:
二叉树的深度优先搜素和广度优先搜索:
1、广度优先搜索(BFS)
宽度优先搜索写为BFS,其过程检验来说就是对每一层节点依次访问,访问这一层浸润下一层,而且每个节点只能访问一次。对于上面的例子来说,广度优先遍历的结果是:3->9->20->15->7。
宽度优先遍历各个节点,需要使用队列这种数据结构,queue的特点是先进先出。
首先将 3 节点插入到队列中,queue(3);
将3节点弹出,同时将3的子节点9,20插入到队列中去,此时queue(9,20);
将9节点弹出,9节点没有子节点,然后将20节点弹出,将20节点的子节点插入到队列中去,此时queue(15,7)
将15节点弹出,15节点没有子节点,将7节点弹出,7节点没有子节点。
广度优先遍历的结果是:3->9->20->15->7
我用list代替queue,pop替代queue从队尾插入元素,pop(0)替代从队首弹出元素:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
queue = [root]
d = []
while queue:
tn = queue.pop(0)
d.append(d)
if tn and tn.left.val:
queue.append(tn.left)
if tn and tn.right.val:
queue.append(tn.right)
2、深度优先搜索
二叉树的的深度优先遍历有前序、中序和后序三种遍历方法,因为树的定义本身就是递归定义,因此用递归去实现三种遍历方法易理解且比较简洁,三种遍历方法的主要思想为:
前序遍历:根节点--->左子树--->右子树
中序遍历:左子树--->根节点--->右子树
后序遍历:左子树--->右子树--->根节点
(1).前序遍历
根据前序遍历的思想,我们写出它的递归版本:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrderBottom(self, root: TreeNode):
if root:
print(root.val)
self.levelOrderBottom(root.left)
self.levelOrderBottom(root.right)
现在写前序遍历的非递归版本,具体思路如下:
根据前序遍历的思想,我们优先遍历根节点,然后左节点再之后右节点,这里我们用栈这个数据结构,先将根节点压入栈中,然后将根节点弹出,根据栈先进后出的规则,将根节点的右孩子压入栈中,再将左孩子压入栈中,之后将左孩子作为根节点,重复上述这个过程。
我们以最上面的那个二叉树举例:
我们首先将3节点压入栈中,此时stack(3);
将3节点弹出,然后先将3节点的右孩子压入到栈中,再将左孩子压入到栈中,此时stack(20,9);
将9节点弹出,因为9节点没有孩子节点,所以继续将20节点弹出,再将20节点的右孩子和左孩子分别压入栈中,此时stack(7,15);
将20节点弹出,15和7节点没有孩子节点,继续弹出15节点和7节点;
所以先序遍历的结果是:3->9->20->15->7
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrderBottom(self, root: TreeNode):
a = [root]
while a:
c = a.pop()
print(c)
if c.right:
a.append(c.right)
if c.left:
a.append(c.left)
(2).中序遍历
根据中序遍历的思思想,我们写出它的递归版本:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrderBottom(self, root: TreeNode):
self.levelOrderBottom(root.left)
print(root.val)
self.levelOrderBottom(root.right)
现在写中序遍历的非递归版本,具体思路如下:
根据中序遍历的顺序,优先访问左子树,然后访问根节点和右子树,但是左子树是根据根节点来的,所以对于任意节点,如果非空,直接储存之,然后判断左子树是否为空,不为空重复上述过程,如果为空,我们访问右子树,我们需要使用栈这种数据结构的支持。对于任意一个节点node,具体步骤如下:
a)访问之,并把节点node入栈,当前节点设置为左孩子;
b)判断当前节点是否为空,不为空重复上述过程,如果为空,取出栈顶节点并出栈,将右孩子设置为当前节点;否则重复a)步骤直到当前节点为空或者栈为空。
代码如下:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
stack = []
pos = root
while pos is not None or stack:
if pos:
stack.append(pos)
pos = pos.left
else:
pos = stack.pop()
print(pos.val)
pos = pos.right
题目:来源-leetcode101.对称二叉树
递归:
解体思路:如果两个二叉树镜像对称,那么一个树的左子树和另一个树的右子树镜像对称。
1.怎么判断一棵树是不是对称二叉树? 答案:如果所给根节点,为空,那么是对称。如果不为空的话,当他的左子树与右子树对称时,他对称。
2.那么怎么知道左子树与右子树对不对称呢?在这我直接叫为左树和右树 答案:如果左树的左孩子与右树的右孩子对称,左树的右孩子与右树的左孩子对称,那么这个左树和右树就对称。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def ismirror(self,tag1,tag2):
if not tag1 and not tag2:
return True
if not tag1 or not tag2:
return False
if tag1.val != tag2.val: #针对第二层的节点
return False
return self.ismirror(tag1.left,tag2.right) and self.ismirror(tag1.right,tag2.left)
def isSymmetric(self, root: TreeNode) -> bool:
return self.ismirror(root,root)
迭代:
方法1:
解题思路:分别取出每一次的所有结点的值放入到列表中,然后判断是不是回文数,如果不是,就返回False
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
queue = [root]
while queue:
b,c = [],[]
for i in queue:
if not i:
c.append(None) #防止出现一边是空的二叉树
continue
b.append(i.left)
b.append(i.right)
c.append(i.val)
if c != c[::-1]:
return False
queue = b
return True
方法2:
解题思路:
除了递归的方法外,我们也可以利用队列进行迭代。队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像。最 初,队列中包含的是 root 以及 root。每次提取两个结点并比较它们的值。然后,将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
queue = [root,root]
while queue:
q1 = queue.pop()
q2 = queue.pop()
if not q1 and not q2:
continue #当节点部分为None时,需要判断其余部分是否镜像相同
if not q1 or not q2:
return False
if q1.val != q2.val:
return False
queue.append(q1.left)
queue.append(q2.right)
queue.append(q1.right)
queue.append(q2.left)
return True