数据结构(Python实现)------ 二叉树
数据结构(Python实现)------二叉树
树的遍历
基本概念
树的遍历 - 介绍
前序遍历
中序遍历
后序遍历
递归和迭代
Python实现
二叉树的前序遍历
栈实现
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
res = []
stack = [root]
while stack:
cur = stack.pop()
res.append(cur.val)
if cur.right:
stack.append(cur.right)
if cur.left:
stack.append(cur.left)
return res
递归实现
class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
二叉树的中序遍历
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
res = []
stack = []
temp = root
while temp or stack:
if temp != None:
stack.append(temp)
temp = temp.left
else:
temp = stack.pop()
res.append(temp.val)
temp = temp.right
return res
二叉树的后续遍历
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def postorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
stack= [root]
res = []
while stack:
cur = stack.pop()
if cur.left:
stack.append(cur.left)
if cur.right:
stack.append(cur.right)
res.insert(0, cur.val)
return res
二叉树的层序遍历
运用递归解决树的问题
基本概念
“自顶向下” 的解决方案
“自顶向下” 意味着在每个递归层级,我们将首先访问节点来计算一些值,并在递归调用函数时将这些值传递到子节点。 所以 “自顶向下” 的解决方案可以被认为是一种前序遍历。 具体来说,递归函数 top_down(root, params) 的原理是这样的:
- return specific value for null node
- update the answer if needed // anwer <-- params
- left_ans = top_down(root.left, left_params) // left_params <-- root.val, params
- right_ans = top_down(root.right, right_params) // right_params <-- root.val, params
- return the answer if needed // answer <-- left_ans, right_ans
例如,思考这样一个问题:给定一个二叉树,请寻找它的最大深度。
我们知道根节点的深度是1。 对于每个节点,如果我们知道某节点的深度,那我们将知道它子节点的深度。 因此,在调用递归函数的时候,将节点的深度传递为一个参数,那么所有的节点都知道它们自身的深度。 而对于叶节点,我们可以通过更新深度从而获取最终答案。 这里是递归函数 maximum_depth(root, depth) 的伪代码:
“自底向上” 的解决方案
总结
Python实现
二叉树的最大深度
递归方法:
递归是最容易想到的一种方法,判断如果传入的节点为空,则返回0,否则返回左节点和右节点的最大值+1。代码如下:
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if root == None:
return 0
return max(self.maxDepth(root.left),self.maxDepth(root.right)) + 1
层次遍历方法:
可以采用层次遍历,每遍历一层,深度值+1。代码如下:
class Solution2(object):
def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if root == None:
return 0
presub = [root]
p = root
sub = []
d = 1
while p!=None or len(presub)!=0:
while len(presub) != 0:
p = presub.pop(0)
if p.left!= None:
sub.append(p.left)
if p.right!=None:
sub.append(p.right)
presub = sub
if len(sub) != 0:
d+=1
else:
return d
sub = []
return d
对称二叉树
# Definition for a binary tree node.
# class TreeNode(object):
# 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
"""
def isSameTree(p,q):
if not p and not q:
return True
if p and q and p.val == q.val:
l = isSameTree(p.left,q.right)
r = isSameTree(p.right,q.left)
return l and r#and 操作,需要l与r皆为true时,才返回真,只用最后一次递归边界return值
else:
return False
if not root:
return True
else:
return isSameTree(root.left,root.right)
路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def hasPathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: bool
"""
if not root:
return False
sum -= root.val
#左右几点都为空,判断是否与sum相等
if not root.left and not root.right:
return sum == 0
return self.hasPathSum(root.left,sum) or self.hasPathSum(root.right,sum)
从中序与后序遍历序列构造二叉树
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def buildTree(self, inorder, postorder):
"""
:type inorder: List[int]
:type postorder: List[int]
:rtype: TreeNode
"""
if not postorder:
return None
root = TreeNode(postorder[-1])
root_index = inorder.index(postorder[-1])
left_inorder = inorder[:root_index]
right_inorder = inorder[root_index+1:]
l_left = len(left_inorder)
left_postorder = postorder[:l_left]
right_postorder = postorder[l_left:-1]
root.left = self.buildTree(left_inorder,left_postorder)
root.right = self.buildTree(right_inorder,right_postorder)
return root
从前序与中序遍历序列构造二叉树
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
if not preorder:
return None
root = TreeNode(preorder[0])
left_inorder = inorder[:inorder.index(root.val)]
right_inorder = inorder[inorder.index(root.val)+1:]
l_left = len(left_inorder)
left_preorder = preorder[1:l_left+1]
right_preorder = preorder[l_left+1:]
root.left = self.buildTree(left_preorder,left_inorder)
root.right = self.buildTree(right_preorder,right_inorder)
return root
填充每个节点的下一个右侧节点指针
输入:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":null,"right":null,"val":4},"next":null,"right":{"$id":"4","left":null,"next":null,"right":null,"val":5},"val":2},"next":null,"right":{"$id":"5","left":{"$id":"6","left":null,"next":null,"right":null,"val":6},"next":null,"right":{"$id":"7","left":null,"next":null,"right":null,"val":7},"val":3},"val":1}
输出:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":{"$id":"4","left":null,"next":{"$id":"5","left":null,"next":{"$id":"6","left":null,"next":null,"right":null,"val":7},"right":null,"val":6},"right":null,"val":5},"right":null,"val":4},"next":{"$id":"7","left":{"$ref":"5"},"next":null,"right":{"$ref":"6"},"val":3},"right":{"$ref":"4"},"val":2},"next":null,"right":{"$ref":"7"},"val":1}
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。
"""
# Definition for a Node.
class Node(object):
def __init__(self, val=0, left=None, right=None, next=None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution(object):
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
#先排除掉不需要处理的情况
if not root or (not root.left and not root.right):
return root
#某一个节点的左孩子的next一定是指向这个节点的右孩子
root.left.next = root.right
#当某一个节点的next不为空的时候,这个节点的右孩子的next一定是指向该节点next的left
if root.next:
root.right.next = root.next.left
#递归处理下一层
self.connect(root.left)
self.connect(root.right)
return root
填充每个节点的下一个右侧节点指针 II
递归,分类讨论:
当一个Node既有左孩子又有右孩子的时候,显然左孩子的next就是右孩子,右孩子的next得在Node的next里往右找,直到某个节点有孩子,这个孩子就是Node.right的next。
当一个Node只有左孩子的时候,左孩子的next得在Node的next里往右找。
当一个Node只有右孩子的时候,右孩子的next得在Node的next里往右找。
所以不妨用一个辅助函数findCousin(node, parent)来找到node.next,其中node是parent的子节点
对于一个需要找Cousin节点的node, 首先看叔叔节点parent.next有没有孩子,
如果有左孩子,那么很好这个左孩子就是结果,
如果没有左孩子但是有右孩子,那么也不错,这个右孩子是结果,
如果parent.next没有孩子,那么糟了,还得继续找更小的叔叔,即parent.next.next……
一直这么找下去,直到找到一个有孩子的叔叔,那么返回这个孩子,或者找完所有的叔叔,它们都没有孩子……
这道题比较关键的地方在于递归部分要先处理右子树再处理左子树,因为根据上面的分析,找一个节点的next需要用它父亲节点的next一路往右找,所以必须先把右边部分搞定,左子树才能利用正确的next关系进行查找。
"""
# Definition for a Node.
class Node(object):
def __init__(self, val=0, left=None, right=None, next=None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution(object):
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
if not root or (not root.left and not root.right):
return root
def findCousin(node,parent):
tmp = parent.next
while(tmp):
if tmp.left:
node.next = tmp.left
break
elif tmp.right:
node.next = tmp.right
break
tmp = tmp.next
if root.left and root.right:
root.left.next = root.right
findCousin(root.right, root)
elif root.left:
findCousin(root.left, root)
elif root.right:
findCousin(root.right, root)
# print root.val, root.right.next
self.connect(root.right)
self.connect(root.left)
return root
二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。
思想:
递归,如果当前节点就是p或q,说明当前节点就是最近的祖先,
如果当前节点不是p或p,就试着从左右子树里找pq。
如果pq分别在一左一右被找到,那么当前节点还是最近的祖先返回root就好了,
否则,返回它们都在的那一边
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
if not root or root == p or root == q:
return root
else:
left = self.lowestCommonAncestor(root.left,p,q)
right = self.lowestCommonAncestor(root.right,p,q)
if left and right:
return root
elif left:
return left
elif right:
return right
else:
return
二叉树的序列化与反序列化
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Codec:
def serialize(self, root):
"""Encodes a tree to a single string.
:type root: TreeNode
:rtype: str
"""
if not root:
return []
return_list = []
current_level = [root]
while len(current_level):
new_level = []
for current_node in current_level:
if current_node:
return_list.append(str(current_node.val))
new_level.append(current_node.left)
new_level.append(current_node.right)
else:
return_list.append(None)
current_level= new_level
return return_list
def deserialize(self, data):
"""Decodes your encoded data to tree.
:type data: str
:rtype: TreeNode
"""
if len(data) == 0:
return None
return_node = TreeNode(int(data[0]))
current_level = [return_node]
data = data[1:]
while len(current_level):
new_level = []
count = 0
for current_node in current_level:
if current_node:
count+=1
if not count:
break
new_level_data = data[:count*2]
data = data[count*2:]
count = 0
for current_node in current_level:
if current_node:
if new_level_data[count]:
current_node.left = TreeNode(int(new_level_data[count]))
count +=1
new_level.append(current_node.left)
if new_level_data[count]:
current_node.right = TreeNode(int(new_level_data[count]))
count += 1
new_level.append(current_node.right)
current_level = new_level
return return_node
# Your Codec object will be instantiated and called as such:
# codec = Codec()
# codec.deserialize(codec.serialize(root))