mysql 实现非递归树_2020-08-26:裸写算法:树的非递归先序遍历。

福哥答案2020-08-26:

方法 1:迭代

算法

从根节点开始,每次迭代弹出当前栈顶元素,并将其孩子节点压入栈中,先压右孩子再压左孩子。

在这个算法中,输出到最终结果的顺序按照 Top->Bottom 和 Left->Right,符合前序遍历的顺序。

算法复杂度

时间复杂度:访问每个节点恰好一次,时间复杂度为 O(N) ,其中 N 是节点的个数,也就是树的大小。

空间复杂度:取决于树的结构,最坏情况存储整棵树,因此空间复杂度是 O(N)。

方法 2:莫里斯遍历

方法基于 莫里斯的文章,可以优化空间复杂度。算法不会使用额外空间,只需要保存最终的输出结果。如果实时输出结果,那么空间复杂度是 O(1)。

算法

算法的思路是从当前节点向下访问先序遍历的前驱节点,每个前驱节点都恰好被访问两次。

首先从当前节点开始,向左孩子走一步然后沿着右孩子一直向下访问,直到到达一个叶子节点(当前节点的中序遍历前驱节点),所以我们更新输出并建立一条伪边 predecessor.Right = root 更新这个前驱的下一个点。如果我们第二次访问到前驱节点,由于已经指向了当前节点,我们移除伪边并移动到下一个顶点。

如果第一步向左的移动不存在,就直接更新输出并向右移动。

算法复杂度

时间复杂度:每个前驱恰好访问两次,因此复杂度是 O(N),其中 N 是顶点的个数,也就是树的大小。

空间复杂度:我们在计算中不需要额外空间,但是输出需要包含 N 个元素,因此空间复杂度为 O(N)。

代码用golang编写,如下:

package test34_preordertraversalimport ("fmt""testing")//https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/er-cha-shu-de-qian-xu-bian-li-by-leetcode///go test -v -test.run TestPreorderTraversalfunc TestPreorderTraversal(t *testing.T) {root := &TreeNode{}root.Val = 1root.Left = &TreeNode{}root.Left.Val = 2root.Right = &TreeNode{}root.Right.Val = 3root.Left.Left = &TreeNode{}root.Left.Left.Val = 4root.Left.Right = &TreeNode{}root.Left.Right.Val = 5root.Right.Left = &TreeNode{}root.Right.Left.Val = 6root.Right.Right = &TreeNode{}root.Right.Right.Val = 7fmt.Println(preorderTraversal1(root))fmt.Println(preorderTraversal2(root))}//Definition for a binary tree node.type TreeNode struct {Val intLeft *TreeNodeRight *TreeNode}//方法 1:迭代//从根节点开始,每次迭代弹出当前栈顶元素,并将其孩子节点压入栈中,先压右孩子再压左孩子。//在这个算法中,输出到最终结果的顺序按照 Top->Bottom 和 Left->Right,符合前序遍历的顺序。//算法复杂度//时间复杂度:访问每个节点恰好一次,时间复杂度为 O(N) ,其中 N 是节点的个数,也就是树的大小。//空间复杂度:取决于树的结构,最坏情况存储整棵树,因此空间复杂度是 O(N)。func preorderTraversal1(root *TreeNode) []int {stack := make([]*TreeNode, 0)output := make([]int, 0)if root == nil {return output}//push 根stack = append(stack, root)for len(stack) > 0 {//popnode := stack[len(stack)-1]stack = stack[0 : len(stack)-1]output = append(output, node.Val)if node.Right != nil {//push右stack = append(stack, node.Right)}if node.Left != nil {//push左stack = append(stack, node.Left)}}return output}//方法 2:莫里斯遍历//方法基于 莫里斯的文章,可以优化空间复杂度。算法不会使用额外空间,只需要保存最终的输出结果。如果实时输出结果,那么空间复杂度是 O(1)。//算法//算法的思路是从当前节点向下访问先序遍历的前驱节点,每个前驱节点都恰好被访问两次。//首先从当前节点开始,向左孩子走一步然后沿着右孩子一直向下访问,直到到达一个叶子节点(当前节点的中序遍历前驱节点),所以我们更新输出并建立一条伪边 predecessor.Right = root 更新这个前驱的下一个点。如果我们第二次访问到前驱节点,由于已经指向了当前节点,我们移除伪边并移动到下一个顶点。//如果第一步向左的移动不存在,就直接更新输出并向右移动。//算法复杂度//时间复杂度:每个前驱恰好访问两次,因此复杂度是 O(N),其中 N 是顶点的个数,也就是树的大小。//空间复杂度:我们在计算中不需要额外空间,但是输出需要包含 N 个元素,因此空间复杂度为 O(N)。func preorderTraversal2(root *TreeNode) []int {output := make([]int, 0)node := rootfor node != nil {if node.Left == nil {//push根output = append(output, node.Val)//右node = node.Right} else {predecessor := node.Leftfor predecessor.Right != nil && predecessor.Right != node {predecessor = predecessor.Right}if predecessor.Right == nil {output = append(output, node.Val)predecessor.Right = nodenode = node.Left} else {predecessor.Right = nilnode = node.Right}}}return output}

敲命令 go test -v -test.run TestPreorderTraversal ,执行结果如下:

43ed6ecf0e9d6b144aff2a184adace07.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值