1. 程式人生 > 其它 >演算法基礎之二叉樹遍歷(前中後)

演算法基礎之二叉樹遍歷(前中後)

二叉樹

前序遍歷

先訪問根節點,再前序遍歷左子樹,再前序遍歷右子樹

中序遍歷

先中序左子樹,在訪問根節點,再中序遍歷右子樹

後序遍歷

先後序遍歷左子樹,再後序遍歷右子樹,再訪問跟節點

解法

遞迴

三種遍歷方式遞迴程式碼基本一致,根據遍歷順序調整結果儲存與遞迴程式碼順序即可

迭代

採用壓棧的方式,核心程式碼基本也是一致的,只是壓棧和結果儲存的時機稍微一點區別

程式碼

// 遞迴模板
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
}