Python 二叉樹先序中序後序遍歷 非遞歸

先序遍歷二叉樹非遞歸

       類似遞歸的思想,遇到一個節點先打印出來,然後依次訪問左右節點。但是非遞歸藉助棧來實現有所不同,應該先打印當前節點,然後依次入棧右節點和左節點,因爲此時棧的插入順序和彈出順序相反。

       節點的結構:

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))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章