演算法基礎之二叉樹遍歷(前中後)
阿新 • • 發佈:2021-07-31
二叉樹
前序遍歷
先訪問根節點,再前序遍歷左子樹,再前序遍歷右子樹
中序遍歷
先中序左子樹,在訪問根節點,再中序遍歷右子樹
後序遍歷
先後序遍歷左子樹,再後序遍歷右子樹,再訪問跟節點
解法
遞迴
三種遍歷方式遞迴程式碼基本一致,根據遍歷順序調整結果儲存與遞迴程式碼順序即可
迭代
採用壓棧的方式,核心程式碼基本也是一致的,只是壓棧和結果儲存的時機稍微一點區別
程式碼
// 遞迴模板 func recursionTraversal(root *TreeNode) (res []int) { if root == nil{ return nil } var recursion func(root *TreeNode) recursion = func(root *TreeNode){ if root == nil{ return } // 前序遍歷 res = append(res,root.Val) postorder(root.Left) postorder(root.Right) // 中序遍歷 postorder(root.Left) res = append(res,root.Val) postorder(root.Right) // 後序遍歷 postorder(root.Left) postorder(root.Right) res = append(res,root.Val) } recursion(root) return } // 前序迭代遍歷 func preorderTraversal(root *TreeNode) []int{ if root == nil { return nil } // 最終返回結果 result := make([]int,0) // 堆疊儲存中間節點 stack := make([]*TreeNode,0) // 當二叉樹左右遍歷節點都為空,堆疊無節點退出迴圈 for root != nil || len(stack) != 0 { // 迴圈 儲存根節點 將節點儲存棧中 繼續讀取左節點 for root != nil { result = append(result,root.Val) stack = append(stack,root) root = root.Left } // 上方迴圈無左節點了 執行stack pop操作 賦值 root 右節點繼續遍歷 node := stack[len(stack)-1] stack = stack[:len(stack)-1] root = node.Right } return result } // 中序迭代遍歷 func inorderTraversal(root *TreeNode) []int { result := make([]int,0) if root == nil{ return result } stack := make([]*TreeNode,0) for len(stack) > 0 || root != nil { // 儲存訪問元素,一直向左 for root != nil{ stack = append(stack,root) root = root.Left } val := stack[len(stack)-1] stack = stack[:len(stack)-1] result = append(result,val.Val) root = val.Right } return result } // 後序迭代遍歷 func postorderTraversal(root *TreeNode) []int { if root == nil{ return nil } result := make([]int,0) stack := make([]*TreeNode,0) var lastVisit *TreeNode for root != nil || len(stack) != 0 { for root != nil{ stack = append(stack,root) root = root.Left } node := stack[len(stack)-1] // 確保不存在右節點或右節點已經彈出後彈出根元素 if node.Right == nil || node.Right == lastVisit{ stack = stack[:len(stack)-1] result = append(result,node.Val) // 標識節點已彈出 lastVisit = node }else{ root = node.Right } } return result }