1. 程式人生 > 實用技巧 >Python改變一行程式碼實現二叉樹前序、中序、後序的迭代遍歷

Python改變一行程式碼實現二叉樹前序、中序、後序的迭代遍歷

Python改變一行程式碼實現二叉樹前序、中序、後序的迭代遍歷

  • 遞迴

  • 今天在做LeetCode的二叉樹前序遍歷題的時候,我看到題目是這樣的:

    • 給定一個二叉樹,返回它的前序遍歷
    • 遞迴方法很簡單,你可以通過迭代演算法完成嗎?
  • 我當時就不樂意了,你這也太高看我了,什麼叫遞迴方法很簡單?沒想到我遞迴方法我也不會吧

  • 經過我冥思苦想終於把以前學資料結構的時候記憶拿回來了

  • 其實真的很簡單,如下:

  • # 前序
    def preorderTraversal(self, root):
        if root is None: return []
        out = [root.val]
        out.extend(self.preorderTraversal(root.left))
        out.extend(self.preorderTraversal(root.right))
        return out
    
    
    # 中序
    def preorderTraversal(self, root):
        if root is None: return []    
        out.extend(self.preorderTraversal(root.left))
        out = [root.val]
        out.extend(self.preorderTraversal(root.right))
        return out
    
    
    # 後序
    def preorderTraversal(self, root):
        if root is None: return []   
        out.extend(self.preorderTraversal(root.left))
        out.extend(self.preorderTraversal(root.right))
        out = [root.val]
        return out
    
  • 這不是我這篇文章的重點,這只是前戲,還有就是遞迴真的很簡單,我就不解釋了

  • 迭代

  • 題目都說遞迴很簡單了,讓我用迭代的方法,那麼我怎麼能示弱呢?

  • 於是我想破我的小腦袋瓜也還是沒有想出來,於是我看了題解。。。終於悟到其中的奧妙

  • 接著就有了下面的程式碼

  • def preorderTraversal(self, root):
        if root is None:
        	return []
        out = []
        stack = [root]
       	while stack:
        	root = stack.pop()
            if root:
            out.append(root.val)
            stack.append(root.right)
            stack.append(root.left)
        return out
    
  • 這也很簡單,幾乎就和官方題解一模一樣,也沒什麼好解釋的吧,但是我把這個方法理解之後看到一個C++大佬的題解說改變一行程式碼就實現前序、中序、後序的迭代遍歷,反正具體的程式碼我也沒看,我就想我用Python來實現一個

  • 於是我就想了想

    • 上面那套程式碼是遇到節點直接把它的值存到輸出數組裡面,這種方法適合前序遍歷,但並不適合中序和後序遍歷。
    • 上面的那種方法是把節點值輸出然後再把右孩子和左孩子依次壓入棧中,我就想我應該也可以把根節點的值也一併的壓入棧中。
    • 根據左孩子、右孩子、根的值壓入棧中的順序不同,從而實現前序、中序、後序的迭代遍歷
  • 因為棧是先進後出,前序遍歷是根、左、右

    • 所以我們先把右孩子壓進去,再壓左孩子,最後再把根的值壓進去
    • 這樣出棧的順序就是根-->左孩子-->右孩子,就實現了前序遍歷
  • # 前序遍歷
    stack.append(root.right)
    stack.append(root.left)
    stack.append(root.val)
    
  • 同理

    • 我們先把右孩子壓進去,再壓根的值,最後再把左孩子壓進去
    • 這樣出棧的順序就是左孩子-->根-->右孩子,就實現了中序遍歷
  • # 中序遍歷
    stack.append(root.right)
    stack.append(root.val)
    stack.append(root.left)
    
  • 再次同理

    • 我們先把根的值壓進去,再壓右孩子,最後再把左孩子壓進去
    • 這樣出棧的順序就是左孩子-->右孩子-->根,就實現了後序遍歷
  • # 中序遍歷
    stack.append(root.val)
    stack.append(root.right)
    stack.append(root.left)
    
  • 綜上

  • 前序遍歷

  • def preorderTraversal(self, root):
        if root is None: 
            return []
        t = type(root)			# 儲存樹的型別
        out = []				# 初始化輸出陣列
        stack = [root]			# 將樹壓入棧中
        while stack:			# 迴圈棧
            root = stack.pop()	        # 根節點等於出棧的節點
            if type(root) != t and root is not None:	# 如果此時root不為樹並且不為空
                out.append(root)				# 將這個數加入輸出陣列中
                continue					# 結束本次迴圈
            if root:      				        # 如果此時root是樹
                stack.append(root.right)			# 將右孩子壓入棧
                stack.append(root.left)			# 將左孩子壓入棧
                stack.append(root.val)			# 將根的值壓入棧
        return out
    
  • 中序遍歷

  • def preorderTraversal(self, root):
        if root is None:
            return []
        t = type(root)
        out = []
        stack = [root]
        while stack:
            root = stack.pop()
            if type(root) != t and root is not None:
                out.append(root)
                continue
            if root:    
                stack.append(root.right)
                stack.append(root.val)					# 中序遍歷
                stack.append(root.left)
        return out
    
  • 後序遍歷

  • def preorderTraversal(self, root):
        if root is None:
            return []
        t = type(root)
        out = []
        stack = [root]
        while stack:
            root = stack.pop()
            if type(root) != t and root is not None:
                out.append(root)
                continue
            if root:    
                stack.append(root.val)					# 後序遍歷
                stack.append(root.right) 
                stack.append(root.left)
        return out
    
  • 以上就是我的思路和理解。

  • 從本質上來說,遞迴遍歷二叉樹和迭代遍歷二叉樹都是一樣的,遞迴遍歷二叉樹是程式幫我們管理棧,迭代遍歷二叉樹是我們手動去維護棧。