二叉树学习指南

前置芝士

二叉树创建

class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode(int x) { val = x; }
  }

前序遍历二叉树的序列化

[problem description]

public class Codec {

    // 把一棵二叉树序列化成字符串
    public String serialize(TreeNode root) {}

    // 把字符串反序列化成二叉树
    public TreeNode deserialize(String data) {}
}

img

序列化:2,1,#,6,3,#,#

[solved]

[java]

public class Main{
    // 代表分隔符的字符
    String SEP=",";
    // 代表 null 空指针的字符
    String NULL="#";
    // 用于拼接字符串
    StringBuilder sb=new StringBuilder();
    /* 将二叉树打平为字符串 */
    //序列化字符串
    void traverse(TreeNode root,StringBuilder sb){
        if(root==null){
            sb.append(NULL).append(SEP);
            return;
        }
        sb.append(root.val).append(SEP);
        traverse(root.left,sb);
        traverse(root.right,sb);
    }
}

前序遍历二叉树的反序列化

[problem description]

String data = "1,2,#,4,#,#,3,#,#,";
String[] nodes = data.split(",");

[solved]

单单前序遍历结果是不能还原二叉树结构的,因为缺少空指针的信息,至少要得到前、中、后序遍历中的两种才能还原二叉树。但是这里的 node 列表包含空指针的信息,所以只使用 node 列表就可以还原二叉树。

public class Main{
    // 代表分隔符的字符
    String SEP=",";
    // 代表 null 空指针的字符
    String NULL="#";
    TreeNode deserialize(String data){
        LinkedList<String> nodes=new LinkedList<>();
        for(String s:data.split(SEP)){
            nodes.addLast(s);
        }
        return dfs(nodes);
    }
    TreeNode dfs(LinkedList<String> nodes){
        if(nodes.isEmpty()) return null;
        String node=nodes.removeFirst();
        if(node.equals(NULL)) return null;
        TreeNode root=new TreeNode(Integer.parseInt(node));
        root.left=dfs(nodes);
        root.right=dfs(nodes);
        return root;
    }
}

后序遍历序列化

[solved]

/* 辅助函数,将二叉树存入 StringBuilder */
void serialize(TreeNode root, StringBuilder sb) {
    if (root == null) {
        sb.append(NULL).append(SEP);
        return;
    }

    serialize(root.left, sb);
    serialize(root.right, sb);

    /****** 后序遍历位置 ******/
    sb.append(root.val).append(SEP);
    /***********************/
}

后序遍历反序列化

[problem description]

img

[solved]

root 的值是列表的最后一个元素。我们应该从后往前取出列表元素,先用最后一个元素构造 root,然后递归调用生成 root 的左右子树。注意,根据上图,从后往前在 nodes 列表中取元素,一定要先构造 root.right 子树,后构造 root.left 子树。

/* 主函数,将字符串反序列化为二叉树结构 */
TreeNode deserialize(String data) {
    LinkedList<String> nodes = new LinkedList<>();
    for (String s : data.split(SEP)) {
        nodes.addLast(s);
    }
    return deserialize(nodes);
}

/* 辅助函数,通过 nodes 列表构造二叉树 */
TreeNode deserialize(LinkedList<String> nodes) {
    if (nodes.isEmpty()) return null;
    // 从后往前取出元素
    String last = nodes.removeLast();
    if (last.equals(NULL)) return null;
    TreeNode root = new TreeNode(Integer.parseInt(last));
    // 限构造右子树,后构造左子树
    root.right = deserialize(nodes);
    root.left = deserialize(nodes);

    return root;
}

中序遍历序列化

[solved]

中序遍历无法反序列化,因为找不到root

/* 辅助函数,将二叉树存入 StringBuilder */
void serialize(TreeNode root, StringBuilder sb) {
    if (root == null) {
        sb.append(NULL).append(SEP);
        return;
    }

    serialize(root.left, sb);
    /****** 中序遍历位置 ******/
    sb.append(root.val).append(SEP);
    /***********************/
    serialize(root.right, sb);
}

层序遍历序列化

[problem description]

img

[solved]

每一个非空节点都会对应两个子节点,那么反序列化的思路也是用队列进行层级遍历,同时用索引 i 记录对应子节点的位置

/* 将字符串反序列化为二叉树结构 */
TreeNode deserialize(String data) {
    if (data.isEmpty()) return null;
    String[] nodes = data.split(SEP);
    // 第一个元素就是 root 的值
    TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));

    // 队列 q 记录父节点,将 root 加入队列
    Queue<TreeNode> q = new LinkedList<>();
    q.offer(root);

    for (int i = 1; i < nodes.length; ) {
        // 队列中存的都是父节点
        TreeNode parent = q.poll();
        // 父节点对应的左侧子节点的值
        String left = nodes[i++];
        if (!left.equals(NULL)) {
            parent.left = new TreeNode(Integer.parseInt(left));
            q.offer(parent.left);
        } else {
            parent.left = null;
        }
        // 父节点对应的右侧子节点的值
        String right = nodes[i++];
        if (!right.equals(NULL)) {
            parent.right = new TreeNode(Integer.parseInt(right));
            q.offer(parent.right);
        } else {
            parent.right = null;
        }
    }
    return root;
}
posted @ 2023-10-24 17:28  White_Sheep  阅读(1)  评论(0编辑  收藏  举报