代码随想录算法训练营第十四天[二刷] | 二叉树的遍历!(94,144,145)

|基本原理:

  1. 满二叉树 #node = 2^n -1
  2. 完全二叉树 底层不一定满但是一定从左往右连续的 eg : heap
  3. BST: 对元素顺序无所谓,对大小有要求left < root . right > root
  4. 平衡BST: abs(height of left - right) <=1

存储:

  1. 链式(LinkedList): root.left & root.right
  2. 线性(Array): = HEAP , 左子节点 2 * n + 1

首先,遍历的顺序: 再定义pre-order, in-order, post-order 的时候,都是根据中间结点的位置来命名。前序(pre)就是说中间结点第一个遍历,中序(in-order)就是中间结点第二个遍历,后序就是最后一个被遍历.

递归(DFS)

写递归, 有3个部分一定要确定:

  1. 确定返回值(二叉树中,至少遍历这块基本都是空,因为结果已经放在了全局变量res中)
  2. 确定终止条件: 假设走到最后一个是什么情况(最普遍的是遍历到的节点为空)
  3. 单层的递归逻辑, 每一次递归中需要作什么

把一个大问题变成一个小问题:
前序递归:先root + 再遍历左边所有的值 + 再遍历右边所有的值
可以写一个helper function, 每次将root的值和需要返回的List放进去
没有helper function , 唯一的不同就是为空的时候因为return value 需要返回list, 所以递归的截止条件满足的时候就return res。 因为我设置res 为全局变量,所以res整体还是不变的:

// res is global var
List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
// return res 和 helper function下 直接return 是一样的效果       
        if (root ==  null) return  res;
            res.add(root.val);      
            preorderTraversal(root.left);
            preorderTraversal(root.right);            
         return res;
}

中序递归:先遍历左边所有的值 + root + 再遍历右边所有的值
这里我就用具有helper function 的方法来写

public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        helper(root, res);
        return res;
    }

    public static void helper(TreeNode root, List<Integer> res){
    //递归的戒截止条件
        if (root == null) return ;     
        //先遍历左子树   
        helper(root.left, res);
        // 中间的val
        res.add(root.val);
        //再遍历右子树  
        helper(root.right, res);
    }

后序遍历:
把遍历的位置换成
先左子树
再右子树
再root
即可

迭代

递归其实就是隐形的调用了栈,所以迭代法就是把栈体现出来
in-order:
我们知道结果List的第一位肯定是最左边的Node,所以要先找到最左边的子结点,加到res里。
但是对于第一个while 循环,二刷才发现,自己理解是有偏差的,又听了卡哥的视频发现正确的思路:
往左边走到最左子节点的while循环的意义 :是为了把所有(所以才有走到空才停止的判定)的点加到stack里,为空之后就开始一个个弹出来开始进行逻辑处理。处理就是说把他的数值加到最后的结果List内,然后找他的右节点(直接让当前父节点 r = r.right 这样就可以让指针到右边的子树)
用2个循环完成, 或者一个循环,内层只是方便把左节点插入到stack里,不用也可以。
外层循环: 因为要保证栈(存储信息的工具)肯定为空,说明遍历完成。 或者当前的节点为空,就说明走到最后了,可以开始准备Pop了.

去模拟栈,具体就是模拟 以何种顺序推进栈内, 再以何种方式推出来,推出来的时候,该点的子节点会被继续推入

pre-order:
这个和后序就是一个插入顺序的事情,辅助结构Stack 因为处理的顺序和遍历的顺序一样,所以并不算很难,按照先右再左push 进去,弹出,完事儿。

post-order:
真正写的时候,发现还是不太熟悉,一直都钻牛角尖的觉得,后序应该最后是root 弹出来,但是root不先拿出来,也没有办法处理数据,也就是说先访问的肯定是root但是他不是最先处理的。那该怎么办?其实这个疑惑就是Inorder的疑惑,只不过后序这里有一个很巧妙的方法:
其实只要保证 左右中 的顺序即可 即中右左的方法输出答案,最后reverse一下即可。这个算是唯一记住的技巧。
因为栈的 FILO 特性, 所以 先放中,弹出来之后,再放左,再放右。 这样弹出来就是中之后先右后左

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值