題目描述:給定一棵二元樹的根節點 root,返回其節點值的前序遍歷(preorder traversal)結果。前序遍歷的順序是:根節點 → 左子樹 → 右子樹。
解題思路:使用迭代搭配顯式堆疊(stack)模擬遞迴行為。核心觀察:堆疊是後進先出(LIFO),要先處理左子樹,就必須先推入右子節點、再推入左子節點,這樣彈出時左子節點會先被處理。
演算法流程:將根節點推入堆疊;每次從堆疊彈出節點,記錄其值;然後先推入右子節點(若存在),再推入左子節點(若存在)。重複直到堆疊為空。此方法避免了系統呼叫堆疊的遞迴開銷,在競賽中也是展示迭代遍歷能力的標準寫法。
時間複雜度:O(n) — 每個節點恰好被訪問(推入與彈出)一次,n 為樹的節點總數。
空間複雜度:O(n) — 最壞情況(完全偏斜樹)堆疊需要存放所有節點;平均情況(平衡樹)為 O(log n),對應樹的高度。
1. If root is null, return empty list 2. Initialize stack with root, result as empty list 3. While stack is not empty: a. Pop node from stack b. Append node.val to result c. If node.right exists, push node.right onto stack d. If node.left exists, push node.left onto stack 4. Return result
方法一:遞迴(Recursive DFS)
最直觀的寫法:preorder(node) 先訪問當前節點,再遞迴呼叫左子樹、右子樹。時間複雜度 O(n),空間複雜度 O(n)(遞迴呼叫堆疊深度等於樹高),程式碼簡潔但有函數呼叫開銷。
方法二:Morris Traversal(莫里斯遍歷) 無需額外堆疊或遞迴,利用樹中的空指標暫時建立「線索」(threaded link)來回溯。時間複雜度 O(n),空間複雜度 O(1),但會暫時修改樹結構(最終會還原),實作較複雜,適合對空間有嚴格限制的場景。