序列化二叉树

题目描述

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

解法一:(存在问题)

根据“重建二叉树”的启发,我们可以通过记录下二叉树的前序遍历和中序遍历(或后序遍历和中序遍历),然后通过两个遍历序列来反序列化二叉树。

public class Solution {
    int i = 0;
    //序列化二叉树
    String Serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        PreOrder(root, sb);
        sb.append("|");
        InfixOrder(root, sb);
        return sb.toString();
    }
    //求前序遍历
    void PreOrder(TreeNode root, StringBuilder sb) {
        if(root == null) {
            return;
        }
        sb.append(root.val);
        sb.append(",");
        PreOrder(root.left, sb);
        PreOrder(root.right, sb);
    }
    //求中序遍历
    void InfixOrder(TreeNode root, StringBuilder sb) {
        if(root == null) {
            return;
        }
        InfixOrder(root.left, sb);
        sb.append(root.val);
        sb.append(",");
        InfixOrder(root.right, sb);
    }
    //反序列化二叉树
    TreeNode Deserialize(String str) {
        int index = str.indexOf("|");
        String[] preOrder = str.substring(0, index).split(",");
        String[] infixOrder = str.substring(index + 1, str.length()).split(",");
        return DeserializeCore(preOrder, infixOrder, 0, preOrder.length - 1);
    }
    TreeNode DeserializeCore(String[] preOrder, String[] infixOrder, int start, int end) {
        if (end - start < 0) {
            return null;
        }
        TreeNode root = new TreeNode(Integer.parseInt(preOrder[i]));
        int index = 0;
        for(index = start; index <= end; index++) {
            if(infixOrder[index].equals(preOrder[i])) {
                break;
            }
        }
        i++;
        root.left = DeserializeCore(preOrder, infixOrder, start, index - 1);
        root.right = DeserializeCore(preOrder, infixOrder, index + 1, end);
        return root;
    }
}

在序列化二叉树的时候一定要加入分隔符,如果直接序列化成Sting|String,如12345|53214的格式,无法解决多位数字的问题,如当节点为12时则会出问题。

同时这个算法存在致命缺点:

1、该方法要求二叉树中不能有数值重复的节点

2、只有当两个序列中的所有数据都读出后才能开始反序列化。如果两个遍历序列的数据是从一个 流里读出来的,那么可能需要较长的时间。

解法二:

之所以前序遍历无法完成反序列化是因为无法很好地处理空节点问题,我们只需要将空节点序列化为特殊字符如#即可。同时,这种反序列化在得到根节点的数值后便可以开始了,无需等待所有数据接收完毕才能开始。

public class Solution {
    StringBuilder sb = new StringBuilder();
    String s = null;
    String Serialize(TreeNode root) {
       if(root == null) {
           sb.append("#" + ",");
           return null;
       }
        sb.append(root.val + ",");
        Serialize(root.left);
        Serialize(root.right);
        return sb.toString();
    }

    TreeNode Deserialize(String str) {
        if(s == null) {
            s = str;
        }
        //考虑空节点
        if(s == null || s.length() <= 0)
            return null;
        int index = s.indexOf(",");
        TreeNode root = null;
        String number = s.substring(0, index);
        s = s.substring(index + 1);
        if(!number.equals("#")) {
            int n = Integer.parseInt(number);
            root = new TreeNode(n);
            TreeNode left = Deserialize(s);
            root.left = left;
            TreeNode right = Deserialize(s);
            root.right = right;
        }
        return root;
    }
}

通过判断序列是否为空来决定反序列化是否终止。

当然也可以通过设置一个计数器来顺序遍历序列,当遍历到最后的的两个空节点时递归停止(序列化序列最后两个必定为空节点)。

public class Solution {
    StringBuilder sb = new StringBuilder();
    int index = -1;
    String Serialize(TreeNode root) {
       if(root == null) {
           sb.append("#" + ",");
           return null;
       }
        sb.append(root.val + ",");
        Serialize(root.left);
        Serialize(root.right);
        return sb.toString();
    }

    TreeNode Deserialize(String str) {
        index++;
        if(str == null)
            return null;
        String[] strr = str.split(",");
        TreeNode root = null;
        if(!strr[index].equals("#")) {
            int n = Integer.valueOf(strr[index]);
            root = new TreeNode(n);
            root.left = Deserialize(str);
            root.right = Deserialize(str);
        }
        return root;
    }
}

解法三:

既然前序遍历考虑空节点可以完成序列化与反序列化,则层序遍历也可以。

public class Solution {
    //序列化二叉树,按层遍历
    String Serialize(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        StringBuilder sb = new StringBuilder();
        if(root == null) {
            return null;
        }
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if(node == null) {
                sb.append("#" + ",");
            }
            else {
                sb.append(node.val + ",");
                queue.add(node.left);
                queue.add(node.right);
            }
        }
        return sb.toString();
    }
    //反序列化二叉树
    TreeNode Deserialize(String str) {
        if(str == null || str.length() == 0) {
            return null;
        }
        int index = 0;
        String[] list = str.split(",");
        Queue<TreeNode> queue = new LinkedList<>();
        TreeNode root = new TreeNode(Integer.parseInt(list[index++]));
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if(list[index].equals("#")) {
                node.left = null;
            }
            else {
                node.left = new TreeNode(Integer.parseInt(list[index]));
                queue.add(node.left);
            }
            index++;
            if(list[index].equals("#")) {
                node.right = null;
            }
            else {
                node.right = new TreeNode(Integer.parseInt(list[index]));
                queue.add(node.right);
            }
            index++;
        }
        return root;
    }
}

按层遍历二叉树一般需要借助队列。

PS:

当判断字符串是否等于“#”时切记使用equals而不是==。参见“Java 中 == 和 equals的区别

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 本系列导航:剑指offer(第二版)java实现导航帖 面试题37:序列化二叉树 题目要求:实现两个函数,分别用来...
    ryderchan阅读 5,312评论 0 1
  • 题目37:序列化二叉树 请实现两个函数,分别用来序列化和反序列化二叉树。将树写入一个文件被称为“序列化”,读取文件...
    stoneyang94阅读 1,805评论 0 0
  • 本文首发于我的个人博客:尾尾部落 题目描述 请实现两个函数,分别用来序列化和反序列化二叉树 解题思路 对于序列化:...
    繁著阅读 3,126评论 0 1
  • 请实现两个函数,分别用来序列化和反序列化二叉树 语言java算法分析: 我们可以采用先序遍历的思想,只是在这里需要...
    克里斯加德纳阅读 3,772评论 0 50
  • 树的概述 树是一种非常常用的数据结构,树与前面介绍的线性表,栈,队列等线性结构不同,树是一种非线性结构 1.树的定...
    Jack921阅读 10,047评论 1 31

友情链接更多精彩内容