题目描述

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

提示: 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

示例 1:


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


示例 2:

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


示例 3:

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


示例 4:

输入:root = [1,2]
输出:[1,2]

来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/

解题思路

本题是想要将树进行序列化和反序列化,主要是看树的遍历。遍历的方式有前序、中序、后序、层次遍历。序列化和反序列化的前提是知道根节点,知道遍历结束位置。根据几种遍历的特点,前序的根是第一位,后序的根在最后一位,层次遍历的根在第一位。只有中序遍历不能确定根的位置。所以本题不能通过中序遍历的方式来解决。其他3中方式如下。

参考来源:https://labuladong.gitbook.io/algo/shu-ju-jie-gou-xi-lie/shou-ba-shou-shua-er-cha-shu-xun-lian-di-gui-si-wei/er-cha-shu-de-xu-lie-hua

解题代码

前序遍历方式

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    public final static String SEP = ",";
    public final static String NULL = "#";

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        serialize(root, sb);
        return sb.toString();
    }

    private static void serialize(TreeNode root, StringBuilder sb) {
        if(root == null) {
            sb.append(NULL).append(SEP);
            return;
        }
        //前序方式
        sb.append(root.val).append(SEP);
        serialize(root.left, sb);
        serialize(root.right, sb);
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        LinkedList<String> list = new LinkedList<>();
        for(String s : data.split(SEP)) {
            list.addLast(s);
        }
        return deserialize(list);
    }

    private static TreeNode deserialize(LinkedList<String> list) {
        if(list.isEmpty()) {
            return null;
        }
        String first = list.removeFirst();
        if(first.equals(NULL)) {
            return null;
        }
        //前序方式
        TreeNode root = new TreeNode(Integer.parseInt(first));
        root.left = deserialize(list);
        root.right = deserialize(list);
        return root;
    }


}

// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));

后序遍历方式

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    public final static String SEP = ",";
    public final static String NULL = "#";

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        serialize(root, sb);
        return sb.toString();
    }

    private static 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);
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        LinkedList<String> list = new LinkedList<>();
        for(String s : data.split(SEP)) {
            list.addLast(s);
        }
        return deserialize(list);
    }

    private static TreeNode deserialize(LinkedList<String> list) {
        if(list.isEmpty()) {
            return null;
        }
        //后序遍历方式
        String first = list.removeLast();
        if(first.equals(NULL)) {
            return null;
        }
        TreeNode root = new TreeNode(Integer.parseInt(first));
        //因为后序遍历右子树靠近跟节点,可以知道右子树结束位置,所以要先对右子树进行递归
        root.right = deserialize(list);
        root.left = deserialize(list);
        return root;
    }


}

// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));

层次遍历方式

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    public final static String SEP = ",";
    public final static String NULL = "#";

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if(root == null) return null;
        StringBuilder sb = new StringBuilder();
        Queue<TreeNode> q = new LinkedList<>();
        //节点依次加入队列,一层一层进行遍历
        q.offer(root);
        while(!q.isEmpty()) {
            TreeNode t = q.poll();

            if(t == null) {
                sb.append(NULL).append(SEP);
                continue;
            }
            sb.append(t.val).append(SEP);
            q.offer(t.left);
            q.offer(t.right);
        }
        
        return sb.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if(data==null || data.isEmpty()) return null;
        String[] nodes = data.split(SEP);
        TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));
        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 = null;
            } else {
                TreeNode l = new TreeNode(Integer.parseInt(left));
                parent.left = l;
                q.offer(l);
            }
            
            String right = nodes[i++];
            if(right.equals(NULL)) {
                parent.right = null;
            } else {
                TreeNode r = new TreeNode(Integer.parseInt(right));
                q.offer(r);
                parent.right = r;
            }
        }
        return root;
    }

}

// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));