【算法手记06】二叉树的遍历

文章详细介绍了二叉树的四种遍历方法(前序、中序、后序和层序),以及如何利用递归计算二叉树的最大深度。此外,还讨论了如何将二叉树展开为链表并保持先序顺序,以及在完美二叉树中填充next指针。
摘要由CSDN通过智能技术生成

递归遍历

  • 前序遍历:中左右
  • 中序遍历:左中右
  • 后序遍历:左右中
    image.png

二叉树的遍历模板如下。

void traverse(TreeNode root) {
    if (root == null) {
        return;
    }
    // 前序位置
    traverse(root.left);
    // 中序位置
    traverse(root.right);
    // 后序位置
}
  • 前序位置就是刚进入节点时的位置
  • 中序位置就是刚遍历完左子树,即将开始遍历右子树的位置
  • 后序位置就是遍历完节点的左右子树后,回到节点的位置。

这几个位置的意义一定要理解清楚,后续做题离不开这些。
image.png

104二叉树的最大深度

image.png
思路:在后序位置计算节点最大深度,最大深度为左右子树的最大深度。

public int maxDepth(TreeNode root) {  
    if(root==null)  return 0;  
    int leftMax = maxDepth(root.left);  
    int rightMax = maxDepth(root.right);  
    return 1 + Math.max(leftMax,rightMax);  
}

114 二叉树展开为链表

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

示例 1:

输入: root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]

示例 2:

输入: root = []
输出: []

示例 3:

输入: root = [0]
输出: [0]

提示:

  • 树中结点数在范围 [0, 2000]
  • -100 <= Node.val <= 100

进阶: 你可以使用原地算法(O(1) 额外空间)展开这棵树吗?

思路:在后序位置处理节点,将节点的左子树放到右子树的位置,左子树置空;随后将原右子树拼接到现右子树的末尾。
在下面这张图中,(2,3,4)这颗树就是最小的操作树,因为它的子结点都是叶子节点了,它是第一个可以操作子结点的后序位置。
因此,只需要考虑怎么处理这颗树即可。
image.png

public void flatten(TreeNode root) {  
    if(root==null)  return;  
    flatten(root.left);  
    flatten(root.right);  
    //后序位置  
    TreeNode left = root.left;  
    TreeNode right = root.right;  
  
    root.left = null;  
    root.right = left;  
  
    //把原右子树拼到现在右子树的末尾  
    TreeNode p = root;  
    while (p.right!=null){  
        p = p.right;  
    }  
    p.right = right;  
  
  
  
}

层序遍历

按层遍历结点,即:
1-2-3-4-5-6-7

image.png
层序遍历的模板也需要记下来,非常重要。

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new LinkedList<>();
        if (root == null) {
            return res;
        }

        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        // while 循环控制从上向下一层层遍历
        while (!q.isEmpty()) {
	        //每层的前序位置
            int sz = q.size();
            List<Integer> level = new LinkedList<>();
            //遍历该层结点
            for (int i = 0; i < sz; i++) {
	            //按顺序处理节点
                TreeNode cur = q.poll();
                level.add(cur.val);
                //节点处理完毕,将其子节点入队,需判空
                if (cur.left != null)
                    q.offer(cur.left);
                if (cur.right != null)
                    q.offer(cur.right);
            }
            res.add(level);
        }
        return res;
    }
}

116 填充结点的右侧节点指针

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL

初始状态下,所有 next 指针都被设置为 NULL

示例 1:

输入: root = [1,2,3,4,5,6,7]
输出: [1,#,2,3,#,4,5,6,7,#]
解释: 给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,‘#’ 标志着每一层的结束。

示例 2:

输入: root = []
输出: []

提示:

  • 树中节点的数量在 [0, 212 - 1] 范围内
  • -1000 <= node.val <= 1000

进阶:

  • 你只能使用常量级额外空间。
  • 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
class Solution {  
    public Node connect(Node root) {  
        if(root==null)  return root;  
        Queue<Node> q = new LinkedList<>();  
        q.offer(root);  
        while (!q.isEmpty()){  
            int len = q.size();  
            for (int i = 0; i < len; i++) {  
                Node temp = q.poll();  
                if(i<len - 1) temp.next = q.peek();  
                //子节点入队  
                if(temp.left!=null) q.offer(temp.left);  
                if(temp.right!=null) q.offer(temp.right);  
            }  
        }  
        return root;  
    }  
  
}
  • 43
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值