一 二叉树遍历
1 先序遍历(pre_order),根左右
2 中序遍历(in_order)左根右
3 后序遍历(post_order)左右根
后序遍历常用于数学计算,如下图
后序遍历这棵树,用堆栈处理表达式。每次遇到操作符时,只需从堆栈中弹出2个元素,计算结果并将结果推回堆栈。
代码实例:
先序遍历
Given a binary tree, return the preorder traversal of its nodes’ values.
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.list=[]
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
a =root
if(a):
self.list.append(a.val)
self.preorderTraversal(a.left)
self.preorderTraversal(a.right)
return self.list
中序遍历
Given a binary tree, return the inorder traversal of its nodes’ values.
class Solution:
def __init__(self):
self.list=[]
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if(root):
self.inorderTraversal(root.left)
self.list.append(root.val)
self.inorderTraversal(root.right)
return self.list
后序遍历
Given a binary tree, return the postorder traversal of its nodes’ values.
class Solution:
def __init__(self):
self.list=[]
def postorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if(root):
self.postorderTraversal(root.left)
self.postorderTraversal(root.right)
self.list.append(root.val)
return self.list
二、层次遍历
层次遍历就是一层一层遍历二叉树
BFS是一种在树或图形等数据结构中遍历或搜索的算法。 该算法从根节点开始,首先访问节点本身。 然后遍历它的邻居,遍历它的第二级邻居,遍历它的第三级邻居,依此类推。
用BFS遍历二叉树就可以得到二叉树的层次遍历。通常我们用队列来帮忙做BFS。
代码实例:
Given a binary tree, return the level order traversal of its nodes’ values. (ie, from left to right, level by level).
代码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 levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
self.result=[]
queue=[]
if(root):
node =root
queue.append(node)
while(queue):
node =queue.pop(0)
self.result.append(node.val)
if(node.left):
queue.append(node.left)
if(node.right):
queue.append(node.right)
return self.result
这样做是有问题的,虽然可以层次遍历二叉树,但是得到的list看不出来二叉树的层次。
代码2:
每一层都创建一个list, 将list 中节点对应的元素组成list 加入list
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
self.result=[]
if(root):
q=[root]
while(q):
self.result.append([n.val for n in q])
new_q=[]
for node in q:
if(node.left):
new_q.append(node.left)
if(node.right):
new_q.append(node.right)
q=new_q
return self.result
三、 递归地解决树问题
通常,我们递归地解决树问题可以自上而下(top down), 也可以自下而上(bottom up)。
“自上而下”解决方案
“自上而下”意味着在每个递归级别中,我们将首先访问节点以获得一些值,并在递归调用函数时将这些值传递给它的子节点。 因此,“自上而下”的解决方案可以被视为一种前序遍历。 具体来说,递归函数top_down(root,params)的工作方式如下:
1. return specific value for null node
2. update the answer if needed // anwer <-- params
3. left_ans = top_down(root.left, left_params) // left_params <-- root.val, params
4. right_ans = top_down(root.right, right_params) // right_params <-- root.val, params
5. return the answer if needed // answer <-- left_ans, right_ans
例如:
例如,考虑这个问题:给定二叉树,找到它的最大深度。
我们知道根节点的深度是1.对于每个节点,如果我们知道节点的深度,我们就会知道它的子节点的深度。 因此,如果我们在递归调用函数时将节点的深度作为参数传递,则所有节点都知道它们自身的深度。 对于叶节点,我们可以使用深度来更新最终答案。 这是递归函数maximum_depth(root,depth)的伪代码:
1. return if root is null
2. if root is a leaf node:
3. answer = max(answer, depth) // update the answer if needed
4. maximum_depth(root.left, depth + 1) // call the function recursively for left child
5. maximum_depth(root.right, depth + 1) // call the function recursively for right child
int answer; // don't forget to initialize answer before call maximum_depth
void maximum_depth(TreeNode* root, int depth) {
if (!root) {
return;
}
if (!root->left && !root->right) {
answer = max(answer, depth);
}
maximum_depth(root->left, depth + 1);
maximum_depth(root->right, depth + 1);
}
“自下而上”解决方案
“自下而上”是另一种递归解决方案。 在每个递归级别中,我们将首先为所有子节点递归调用函数,然后根据返回值和根节点本身的值得出答案。 这个过程可以看作是一种后序遍历。 通常,“自下而上”递归函数bottom_up(root)将如下所示:
1. return specific value for null node
2. left_ans = bottom_up(root.left) // call function recursively for left child
3. right_ans = bottom_up(root.right) // call function recursively for right child
4. return answers // answer <-- left_ans, right_ans, root.val
让我们继续讨论关于最大深度的问题,但是使用不同的思维方式:对于树的单个节点,根据自身的子树的最大深度x是多少?
如果我们知道根据其左子节点的子树的最大深度l和根据其右子节点的子树的最大深度r,我们可以回答上一个问题吗? 当然是的,我们可以选择它们之间的最大值加1来获得以所选节点为根的子树的最大深度。 即x = max(l,r)+ 1。
这意味着对于每个节点,我们可以在解决其子问题后得到答案。 因此,我们可以使用“自下而上”的解决方案来解决这个问题。 这是递归函数maximum_depth(root)的伪代码:
1. return 0 if root is null // return 0 for null node
2. left_depth = maximum_depth(root.left)
3. right_depth = maximum_depth(root.right)
4. return max(left_depth, right_depth) + 1 // return depth of the subtree rooted at root
int maximum_depth(TreeNode* root) {
if (!root) {
return 0; // return 0 for null node
}
int left_depth = maximum_depth(root->left);
int right_depth = maximum_depth(root->right);
return max(left_depth, right_depth) + 1; // return depth of the subtree rooted at root
}
总结:
理解递归并找出问题的递归解决方案并不容易。
当遇到树问题时,思考下面连个问题:能确定一些参数来帮助节点了解节点自身的答案吗? 是否可以使用这些参数和节点本身的值来确定解析其子节点的参数应该是什么? 如果答案都是肯定的,请尝试使用“自上而下”的递归解决方案解决此问题。
或者可以通过这种方式思考问题:对于树中的节点,如果知道其子节点的答案,可以计算节点的答案吗? 如果答案是肯定的,那么从下往上递归地解决问题可能是一个好方法。
在以下部分中,我们将为您提供几个经典问题,以帮助您更好地理解树结构和递归。
代码实例
1 Maximum Depth of Binary Tree
Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
Note: A leaf is a node with no children.
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if(root == None):
return 0
left_ans=self.maxDepth(root.left)
right_ans=self.maxDepth(root.right)
return max(left_ans, right_ans)+1