请实现两个函数,分别用来序列化和反序列化二叉树。
示例:
你可以将以下二叉树:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof
序列化的操作:二叉树的层序遍历,需要利用到队列这个数据结构
1、定义StringBuilder对象,用于字符串的拼接,通过观察序列化时返回的字符串模式,那么先将" [ “拼接到stringbuilder对象中
1、将根节点压入到队列中
2、当队列不为空的时候,那么就从队列中跳出一个节点,如果这个节点不为空,那么就将这个节点的左右子节点压入到队列中,然后将这个节点的值拼接到字符串的后面即将(root.val + ","这个字符串拼接,同样需要逗号),否则,如果这个节点为空,那么就直接将"null,”(注意有逗号)添加到字符串中。
3、层序遍历完成之后,需要将字符串最后的逗号删除,然后再最后还需要添加" ] "才可以.
重点讲解反序列化的操作:
这时候我们来想一下,如果题目给出了一个数组,然后要你来构建一棵二叉树你会怎样做呢?
聪明的你应该可以想到,如果下标为 i 的节点作为父节点,那么它的左子节点就是2 * i + 1,右子节点就是2 * i + 2(值得注意的是,这里是从下标为0开始遍历的,如果是从下标为1开始遍历的话,那么它的左子节点的下标就是2 * i,右子节点的下标就是2 * i + 1)。
所以这一道题考察的就是这个知识点,但是又会有所不同。至于为什么不同,当你写好代码,然后去提交的死后,就会给出一个例子,表示无法通过。请看下图的例子:
如果输入的例子是这样的化,那么序列化之后返回来的字符串是这样的:[1,2,3,null,null,4,5,7,8,null,null,null,null,null,null],然后如果根据上面的方式构建二叉树的时候,和正确的答案相比,少了一些节点。所以表明了这种时候不在适用上面的方式构建二叉树。这是为什么?
好的,我们来想想什么情况下才可以利用上面的方式顺序构建二叉树呢?答案是只有是一个完全二叉树的时候才可以利用上面的方式构建二叉树,但是明显这里给出的并不是完全二叉树。所以这就是我们需要考虑的地方了。
由上面给出的序列化字符串,我们尝试着构建一棵二叉树:
所以对应的步骤不是根据上面的关系构建二叉树:在本例中构建二叉树的基本步骤:
1、定义一个变量k,初始值是序列的长度,在上面的例子中是15
2、从下往上根据字符串的值构建节点,如果字符串是null,那么这个节点就是null,否则这个字符串不为null,例如8,那么就新建一个节点,节点的值就是这个字符串对应的整数。然后将更新这个节点的左右字节,执行下面的操作
k -= 1;
node[i].right = node[k];
k -= 1;
node[i].left = node[k];
3、构建完毕之后,将node[0]返回即可
对应的代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if(root == null)
return "[]";//如果树为空,那么就返回[]
StringBuilder str = new StringBuilder();//定义一个stringBuilder对象
Queue<TreeNode> queue = new LinkedList<TreeNode>();
str.append("[");
int i;
TreeNode cur = root;
queue.offer(cur);
while(!queue.isEmpty()){
//队列不为空的时
cur = queue.poll();
if(cur != null){
str.append(cur.val +",");
queue.offer(cur.left);
queue.offer(cur.right);//由于添加左右子节点的时候并没有判断这个节点是否为空,所以跳出的时候需要判断当前这个节点是否为空
}else
str.append("null,");
}
str.delete(str.length() - 1,str.length());//删除最后一个逗号
str.append("]");
return str.toString();
}
// Decodes your encoded data to tree.
//通过数组构建一个二叉树
public TreeNode deserialize(String data) {
//System.out.println(data); 检验获得的序列
//获取一个字符串数组
data = data.trim();//去除字符串前后的空格
//删除字符串前后的中括号
data = data.substring(1);
data = data.substring(0,data.length() - 1);
/*
这个需要注意,因为输入的序列是[]的时候,那么去掉前后的中括号,那
么就是一个空字符串,所以直接返回null
*/
if(data.length() == 0)
return null;
String[] str = data.split(",");//将整个字符串分割成为字符串数组
TreeNode[] node = new TreeNode[str.length];
int i,len,k;
len = str.length;
k = str.length;
//遍历字符串,构建节点数组
for(i = len - 1; i >= 0; i--){
if(!"null".equals(str[i])){
//如果这个字符串不是null,那么就构建新节点,然后调整它的左右子节点
node[i] = new TreeNode(Integer.parseInt(str[i]));
k -= 1;
node[i].right = node[k];
k -= 1;
node[i].left = node[k];
}else{
node[i] = null;
}
}
return node[0];
}
}
// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));
运行结果: