二叉樹的中序遍歷,每層遍歷,以及Z字形遍歷
leetcode中,二叉樹也是一塊重點,對於樹結構衍生出的問題,一般用遞迴的方法會比較多。
如上圖的二叉樹:
中序遍歷:左-根-右的順序,結果是[4,2,5,1,6,3]
每層遍歷:從最上面那層往下面讀,結果是[1,2,3,4,5,6]
Z字形遍歷:和每層遍歷差不多,只是走Z字,結果是[1,3,2,4,5,6]
二叉樹的中序遍歷
對於二叉樹的中序遍歷,就是左-根-右這種遍歷順序。
有遞迴和迭代寫法:非遞迴就用棧來實現
res, stack = [], [] while True: while root: stack.append(root) root = root.left if not stack: return res node = stack.pop() res.append(node.val) root = node.right
我們看棧的情況,while true保證了直到棧為空(if not stack)的時候我們結束迴圈,這時候我們已遍歷棧中所有所有元素。
while root讓我們一直會保證左邊的元素會先進棧,直到左邊沒有元素為止,.pop()彈出後入棧的,後入棧的是最底層的左側元素。
比如第一次while true迴圈,1,2,4先進stack棧,4的左邊沒有元素,所以把4先出棧到res裡,再將root更新成4的右孩子,現在stack: [1,2], res: [4]
第二次while true迴圈,4的右孩子不存在,會執行2出棧,將root更新成2的右孩子,現在stack: [1], res: [4,2]
第三次 while true迴圈, 5進stack棧,5的左邊沒有元素,5出棧到res裡,將root更新成5的右孩子,stack: [1], res:[4,2,5]
…
這個的思想就是,while root和root=root.left保證了左子樹的元素紛紛統統入棧,當我們要考慮一個元素的右孩子時,就說明這個元素已經被我們出棧了。一個元素的右孩子也為空就說明我們已經走到了最左側,應該往上一層考慮了。這裡的root = node.right很巧妙(下一次迴圈與這一次計算結果有關,迭代)。
遞迴寫法:
def inorderTraversal1(self, root):
res = []
self.helper(root, res)
return res
def helper(self, root, res):
if root:
self.helper(root.left, res)
res.append(root.val)
self.helper(root.right, res)
這個還是挺直觀的,按左-根右的順序呼叫函式helper(),函式呼叫棧會是helper(1.left), append(1), helper(1.right),再對helper(1.left)的函式呼叫棧進行分析,總是左-根-右的順序。
每層遍歷
要求輸出的是一個二維列表,每個元素是每層元素所組成的列表。
比如示例就應該輸出[[1],[2,3],[4,5,6]]
def levelOrder(self, root):
if not root:
return []
ans, level = [], [root]
while level:
ans.append([node.val for node in level])
temp = []
for node in level:
temp.extend([node.left, node.right])
level = [leaf for leaf in temp if leaf] #只把非None的孩子新增進去
return ans
思想就是開枝散葉的思想,有兩個列表很關鍵,一個是結果列表res存我們的結果,一個是每層元素列表level存每層的樹結點元素。只要這層不是空的,我就把這層元素新增進ans裡,再用extend方法將孩子列表做好(對每個本層元素都開枝散葉它下層元素),並更新層元素列表。
Z字形遍歷
要求輸出的是一個二維列表,每個元素是每層元素所組成的列表。
比如示例就應該輸出[[1],[3,2],[4,5,6]]
思想和上述一樣,就是加個flag對第偶數次遍歷反序
def zigzagLevelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
if not root:
return []
ans, level = [], [root]
flag = 1
while level:
ans.append([node.val for node in level][::flag]) #偶數次反序
temp = []
for node in level:
temp.extend([node.left, node.right])
level = [leaf for leaf in temp if leaf] #只把非None的孩子新增進去
flag *= -1
return ans
總結一下:
1.對於樹的中序遍歷,遞迴好寫很多,迭代不太直觀
2.對於樹的每層遍歷,extend一次加多個元素,level = [leaf for leaf in temp if leaf] 這個寫的不錯
3.在Z字形遍歷中,flag的妙用,我一開始想的話就會用counter,迴圈一次加1,如果偶數次就逆向輸出,程式碼太不簡潔了。