一 二叉樹遍歷
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