序列化二叉树

序列化二叉树

题目描述

请实现两个函数,分别用来序列化和反序列化二叉树。例如:

image

序列化为 "[1,2,3,null,null,4,5]"("[1,2,3,null,null,4,5,null,null,null,null]")

题目分析

返回结果分析

序列化

序列化二叉树返回的结果是字符串类型,但每次访问一个节点只能得到一个节点的结果,但是为了方便把null加入结果集的操作,这里就使用StringBuilder。

显然,遍历序列的结果与一般的二叉树层次遍历很相似,层次遍历得到的结果是[1 , 2 , 3 , 4 , 5],是没有null值的,所以可以借鉴层次遍历的思想,这里先回顾一下二叉树的层次遍历。

反序列化

有个关键的步骤是,如何从一个字符串中获取到每一个元素,首先使用subString把头和尾的 [ ]去掉,再使用split,官方文档的解释是这样的:

image

image
也就是说根据给定的正则表达式分割字符串,在这里这样用:

String[] elements = data.substring(1,data.length() - 1).split(",");

也就是说只要匹配到了‘ , ’就分割一个子字符串放进新的字符串数组中,拿到了每一个元素就好办了,后面也是相同的,只要判断然后对应创建就可以了

过程分析

层次遍历

层次遍历使用了一个队列,让根节点先入队,每出队一个节点,就把这个节点的数据放进结果集,并且把他的孩子入队(如果不为空),详细步骤如下:

辅助队列 1 1出队放入结果集 把1的孩子(2,3)入队 结果集 1
辅助队列 2 3 2出队放入结果集 2的孩子(null,null)不入队 结果集 1 2
辅助队列 3 3出队放入结果集 把3的孩子(4,5)入队 结果集 1 2 3
辅助队列 4 5 4出队放入结果集 4的孩子(null,null)不入队 结果集 1 2 3 4
辅助队列 5 5出队放入结果集 5的孩子(null,null)不入队 结果集 1 2 3 4 5

序列化

序列化其实就是一个带有null值的层次遍历(不是标准的,只是把叶子节点的null值加入结果集)如图:

image

序列化

把二叉树转换为遍历序列加强版的过程

思路

由上面的分析可以进行改进。在层次遍历中,条件是取出队列中的元素,并且放入结果集。

在序列化中,只需要把取出来的元素加上一层判断即可,如果这个节点不为空,则加入值,如果为空则加入null

queue 1 1加入结果集 把1的孩子(2,3)入队 结果集 1
queue 2 3 2加入结果集 把2的孩子(null,null)加入 结果集 1,2
queue 3 null null 3加入结果集 把3的孩子(4,5)入队 结果集 1,2,3,null,null
queue 4 5 4加入结果集 把4的孩子(null,null)加入 结果集 1,2,3 ,null,null,4
queue 5 null null 5加入结果集 把5的孩子(null,null)加入 结果集 1,2,3,null,null,4,5
queue null null null null null加入结果集 \ 结果集 1,2,3,null,null,4,5,null,null,null,null

代码实现

// Encodes a tree to a single string.
public String serialize(TreeNode root) {
    StringBuilder sb = new StringBuilder();
    if (root == null)
        return "[]";
    else {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        sb.append("[");
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            if (node != null){
                sb.append(node.val);
                queue.offer(node.left);
                queue.offer(node.right);
            }
            else
                sb.append("null");
            sb.append(",");
        }
        sb.append("]");
        sb.deleteCharAt(sb.length() - 2);
    }
    return sb.toString();
}

反序列化

把遍历数组恢复为二叉树的过程

思路

利用好[无论数组中哪一位加入了树中,index总是会向后移动一位]这个特点,就好了

代码实现

// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
    if ("[]".equals(data))
        return null;
    String[] elements = data.substring(1,data.length() - 1).split(",");
    Queue<TreeNode> queue = new LinkedList<>();
    int index = 1;
    TreeNode root = new TreeNode(Integer.parseInt(elements[0]));
    queue.offer(root);
    while (!queue.isEmpty()){
        TreeNode node = queue.poll();
        if (!"null".equals(elements[index])){
            node.left = new TreeNode(Integer.parseInt(elements[index]));
            queue.offer(node.left);
        }
        index++;
        if (!"null".equals(elements[index])){
            node.right = new TreeNode(Integer.parseInt(elements[index]));
            queue.offer(node.right);
        }
        index++;
    }
    return root;
}

测试用例

public static void main(String[] args) {
    //定义一棵树
    TreeNode e = new TreeNode(5,null,null);
    TreeNode d = new TreeNode(4,null,null);
    TreeNode c = new TreeNode(3,d,e);
    TreeNode b = new TreeNode(2,null,null);
    TreeNode a = new TreeNode(1,b,c);

    //定义一个遍历序列
    String data = "[1,2,3,null,null,4,5,null,null,null,null]";
    //创建实例
    serNDeser serial = new serNDeser();
    //查看二叉树序列化得到的结果
    System.out.println(serial.serialize(a));
    //查看序列化结果是否与测试用例的字符串等值
    System.out.println(serial.serialize(a).equals(data));
    //查看通过把测试用例反序列化得到的结果进行序列化,查看(序列化函数和反序列化函数是否是可逆的)
    System.out.println(serial.serialize(serial.deserialize(data)));
}

image

posted @ 2021-05-10 20:46  先破防再敲  阅读(146)  评论(0)    收藏  举报