二叉树的前序中序后序遍历

二叉树的前序遍历

根节点——左子树——右子树的方式遍历二叉树。

方法1:递归

func preorderTraversal(root *TreeNode) (vals []int) {
    var preorder func(*TreeNode)
    preorder = func(node *TreeNode) {
        if node == nil {
            return
        }
        vals = append(vals, node.Val)
        preorder(node.Left)
        preorder(node.Right)
    }
    preorder(root)
    return
}

 

 

方法2:迭代

使用一个栈来模拟迭代的过程。首先将根节点入栈,然后在循环中,从栈中弹出一个节点并将其值添加到结果列表中。接着,如果存在右子节点,将右子节点入栈;如果存在左子节点,将左子节点入栈。通过这种方式,我们可以实现前序遍历的顺序。

func preorderTraversal(root *TreeNode) []int {
	var result []int
	if root == nil {
		return result
	}

	stack := []*TreeNode{root}
	for len(stack) > 0 {
		node := stack[len(stack)-1]
		stack = stack[:len(stack)-1]

		result = append(result, node.Val)

		if node.Right != nil {
			stack = append(stack, node.Right)
		}
		if node.Left != nil {
			stack = append(stack, node.Left)
		}
	}

	return result
}

 

复杂度分析

时间复杂度:O(n)O(n),其中 nn 是二叉树的节点数。每一个节点恰好被遍历一次。

空间复杂度:O(n)O(n),为迭代过程中显式栈的开销,平均情况下为 O(\log n)O(logn),最坏情况下树呈现链状,为 O(n)O(n)。

 

二叉树的中序遍历

按照访问左子树——根节点——右子树的方式遍历这棵树

方法1:递归版本

func inorderTraversal(root *TreeNode) (res []int) {
    var inorder func(node *TreeNode)
    inorder = func(node *TreeNode) {
        if node == nil {
            return
        }
        inorder(node.Left)
        res = append(res, node.Val)
        inorder(node.Right)
    }
    inorder(root)
    return
}

 

方法2:迭代版本

使用一个栈来模拟迭代的过程。首先,将根节点及其所有左子节点依次入栈,直到遍历到最左的叶子节点。然后,从栈中弹出一个节点,并将其值添加到结果列表中。接着,处理弹出节点的右子节点,重复上述过程,直到所有节点都被遍历。

func inorderTraversal(root *TreeNode) []int {
	var result []int
	if root == nil {
		return result
	}

	stack := []*TreeNode{}
	node := root
	for node != nil || len(stack) > 0 {
		// 将当前节点及其左子节点入栈
		for node != nil {
			stack = append(stack, node)
			node = node.Left
		}

		// 弹出栈顶节点,将其值添加到结果列表中
		node = stack[len(stack)-1]
		stack = stack[:len(stack)-1]
		result = append(result, node.Val)

		// 处理右子节点
		node = node.Right
	}

	return result
}

复杂度分析

时间复杂度:O(n)O(n),其中 nn 为二叉树节点的个数。二叉树的遍历中每个节点会被访问一次且只会被访问一次。

空间复杂度:O(n)O(n)。空间复杂度取决于栈深度,而栈深度在二叉树为一条链的情况下会达到 O(n)的级别。

 

二叉树的后序遍历

按照访问左子树——右子树——根节点的方式遍历这棵树。

方法1:递归版本

func postorderTraversal(root *TreeNode) (res []int) {
    var postorder func(*TreeNode)
    postorder = func(node *TreeNode) {
        if node == nil {
            return
        }
        postorder(node.Left)
        postorder(node.Right)
        res = append(res, node.Val)
    }
    postorder(root)
    return
}

 

方法2:迭代版本

首先,将根节点及其所有左子节点依次入栈,直到遍历到最左的叶子节点。然后,检查栈顶节点的右子节点。如果右子节点存在且未被访问过,则将右子节点设为当前节点,继续入栈左子节点。如果右子节点不存在或已被访问过,则弹出栈顶节点,并将其值添加到结果列表中。重复这个过程,直到栈为空。

func postorderTraversal(root *TreeNode) []int {
	var result []int
	if root == nil {
		return result
	}

	stack := []*TreeNode{}
	var prev *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 != prev {
			root = node.Right
		} else {
			// 否则,弹出栈顶节点并将其值添加到结果列表中
			stack = stack[:len(stack)-1]
			result = append(result, node.Val)
			prev = node // 更新上一个访问的节点
		}
	}

	return result
}

复杂度分析

时间复杂度:O(n)O(n),其中 nn 是二叉搜索树的节点数。每一个节点恰好被遍历一次。

空间复杂度:O(n)O(n),为迭代过程中显式栈的开销,平均情况下为 O(\log n)O(logn),最坏情况下树呈现链状,为 O(n)O(n)。

 

posted @ 2021-04-03 23:02  zqlucky  阅读(206)  评论(0编辑  收藏  举报