先序遍歷二叉樹非遞歸
類似遞歸的思想,遇到一個節點先打印出來,然後依次訪問左右節點。但是非遞歸藉助棧來實現有所不同,應該先打印當前節點,然後依次入棧右節點和左節點,因爲此時棧的插入順序和彈出順序相反。
節點的結構:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
先序遍歷的Python代碼:
def pre_order(head):
'''
二叉樹先序遍歷非遞歸實現
:param head: 頭節點
:return: result列表類型
'''
if not head: # 空
return []
stack, result = [], []
stack.append(head)
while len(stack) != 0:
node = stack.pop() # 先序 遇到就先輸出
result.append(node.val)
# 棧的彈出順序與入棧順序相反 因此先入右再入左
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
中序遍歷二叉樹非遞歸
中序遍歷就不能馬上打印當前節點了,得先打印左孩子的節點,所以得先把有左孩子的節點壓棧。從頭結點開始,不斷把有左孩子的節點壓棧,直到左孩子爲空,這樣能保證先打印出左下角的節點。如果當前節點沒有左孩子了,就出棧打印一個出來。如果這個節點有右節點,就繼續上一步驟,對有左子樹的瘋狂壓棧。
複雜點來說,就是把有左節點的瘋狂壓棧,沒了就彈一個出來打印,再看看有沒有右節點,有就轉到右節點,然後再重複左節點的瘋狂壓棧~~~
def mid_order(head):
'''
二叉樹中序遍歷非遞歸實現
1.當前節點如有左節點就不斷壓棧 無左節點就可以出棧打印
2.打印出棧的節點若有右子樹則將右節點執行1的步驟
:param head: 頭結點
:return: result列表類型
'''
if not head: #空
return []
stack, result = [], []
node = head
# 循環條件:1.棧非空則還可以輸出 2.棧空但是節點非空說明還有節點可以壓棧
while node or len(stack) != 0:
if not node: # 如果節點爲空 證明沒有左子樹 彈出一個
node = stack.pop()
result.append(node.val)
node = node.right #嘗試是否有右節點
else: # 節點非空 壓棧 嘗試是否有左子樹
stack.append(node)
node = node.left
return result
後序遍歷二叉樹非遞歸
後序遍歷是 左-右-中 的順序,反過來就是 中-右-左,這就是二叉樹鏡像(左右節點互換)的先序遍歷順序。也就是說,鏡像二叉樹的先序遍歷逆序後就是二叉樹後序遍歷的順序。所以在剛纔先序遍歷的代碼基礎上,改一下左右節點入棧順序,再在最後逆序一下就可以了。
def post_order(head):
'''
後序遍歷二叉樹非遞歸 後序遍歷是 左-右-中
反過來就是 中-右-左 其實就是先序遍歷鏡像二叉樹(即左右互換)
:param head: 頭節點
:return: result[::-1] 逆序
'''
if not head:
return []
stack, result = [], []
stack.append(head)
while len(stack) != 0:
node = stack.pop() # 先序 遇到就先輸出
result.append(node.val)
# 先壓棧左節點再壓右節點 所以輸出就是先右後左
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return result[::-1] # 將 中-右-左 逆序變爲 左-右-中
最後附上全部代碼,含測試案例
# -*- coding:utf-8 -*-
'''
author: James_J
time: 2020/02/21
'''
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def pre_order(head):
'''
二叉樹先序遍歷非遞歸實現
:param head: 頭節點
:return: result列表類型
'''
if not head: # 空
return []
stack, result = [], []
stack.append(head)
while len(stack) != 0:
node = stack.pop() # 先序 遇到就先輸出
result.append(node.val)
# 棧的彈出順序與入棧順序相反 因此先入右再入左
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
def mid_order(head):
'''
二叉樹中序遍歷非遞歸實現
1.當前節點如有左節點就不斷壓棧 無左節點就可以出棧打印
2.打印出棧的節點若有右子樹則將右節點執行1的步驟
:param head: 頭結點
:return: result列表類型
'''
if not head: #空
return []
stack, result = [], []
node = head
# 循環條件:1.棧非空則還可以輸出 2.棧空但是節點非空說明還有節點可以壓棧
while node or len(stack) != 0:
if not node: # 如果節點爲空 證明沒有左子樹 彈出一個
node = stack.pop()
result.append(node.val)
node = node.right
else: # 節點非空 壓棧 嘗試是否有左子樹
stack.append(node)
node = node.left
return result
def post_order(head):
'''
後序遍歷二叉樹非遞歸 後序遍歷是 左-右-中
反過來就是 中-右-左 其實就是先序遍歷鏡像二叉樹(即左右互換)
:param head: 頭節點
:return: result[::-1] 逆序
'''
if not head:
return []
stack, result = [], []
stack.append(head)
while len(stack) != 0:
node = stack.pop() # 先序 遇到就先輸出
result.append(node.val)
# 先壓棧左節點再壓右節點 所以輸出就是先右後左
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return result[::-1] # 將 中-右-左 逆序變爲 左-右-中
if __name__ == '__main__':
l1 = TreeNode(1)
l2 = TreeNode(2)
l3 = TreeNode(3)
l4 = TreeNode(4)
l5 = TreeNode(5)
l6 = TreeNode(6)
l1.left = l2
l1.right = l3
l2.left = l4
l2.right = l5
l3.left = l6
print('pre_order', pre_order(l1))
print('mid_order', mid_order(l1))
print('post_order', post_order(l1))