这道题进一步考察了对二叉树的理解。
一开始此题没有做出来,最后看答案写了出来。
答案来自手画图解』二叉树的序列化与反序列化 | 剖析两种解法
答案给了广度遍历和深度遍历两种方案。
下面简略的解释一下两种解法。
总的来说,两种解法共同考虑的都是,在序列化时保护好 null
值的位置输出,来记录树的结构,以便反序列化恢复。
DFS
对于深度遍历来说,序列化的过程就是先序遍历的过程。这个无需多言。但是反序列化过程怎么做的呢?
由于序列化过程生成了大量的 null 值,导致我在反序列化过程主动放弃了这种解法。
其实在序列化过程是递归,那么反序列化同样的也是进行递归。
将序列化的字符串切割成数组,则数组第一个数即可以当成父节点。父节点之后两个数则为子节点。每次操作完前三个节点的关系后,弹出第一个节点,进入下一层递归。
BFS
这种解法,最后我的 BFS 同样会输出多余的 null 值。这让我很烦恼,因为题目给的实例里面,最后一层节点并没有发生输出。
其实 BFS 则是研究序列化后的数组的规律。
数组第一个数为父,接下来两个数为子。父亲节点索引每次 + 1,子节点索引每次 + 2。
需要注意的是,在实际编码中,千万不可通过遍历数组来创建父节点。否则各个父节点之间都是没有联系的。。。。
而应该,将上一次循环的子节点当做本次循环的父节点。这里我用了一个队列来保存父节点。
具体代码如下:
public class Answer2 {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
StringBuffer sb = new StringBuffer();
sb.append("[");
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode poll = queue.poll();
if (poll == null) {
sb.append("null");
} else {
sb.append(String.valueOf(poll.val));
queue.offer(poll.left);
queue.offer(poll.right);
}
if (!queue.isEmpty()) {
sb.append(",");
}
}
return sb + "]";
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
String[] nodes = data.replace("[", "").replace("]","").split(",");
Queue<TreeNode> parent = new LinkedList<>();
int childIndex = 1;
TreeNode root = null;
if (!nodes[0].equals("null")) {
root = new TreeNode(Integer.parseInt(nodes[0]));
}
parent.offer(root);
while (childIndex <= nodes.length - 1) {
TreeNode father = parent.poll();
if (father != null) {
if (!nodes[childIndex].equals("null")) {
father.left = new TreeNode(Integer.parseInt(nodes[childIndex]));
parent.offer(father.left);
}
if (!nodes[childIndex + 1].equals("null")) {
father.right = new TreeNode(Integer.parseInt(nodes[childIndex + 1]));
parent.offer(father.right);
}
}
childIndex += 2;
}
return root;
}
}
具体参考上面引用的文章,说明得很详细。