题目
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 /
反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。提示: 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode
序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。
思路
方法一:DFS | 深度优先搜索
(1)序列化:
- 采用递归的思想,遍历选择前序遍历,是因为 根∣左∣右 的打印顺序,在反序列化时更容易定位出根节点的值。
- 遇到
null
节点也要翻译成特定符号,反序列化时才知道这里是null
,这里用"X"
表示null
。
(2)反序列化:
- 定义函数
buildTree
用于还原二叉树,传入由序列化字符串转成的list
数组 - 逐个
pop
出list
的首项,构建当前子树的根节点,顺着list
,构建顺序是根节点→左子树→右子树。 - 如果弹出的字符为 “X”,则返回 null 节点。
- 如果弹出的字符是数值,则创建root节点,并递归构建root的左右子树,最后返回root。
java代码如下:
class Codec{
//序列化
public String serialize(TreeNode root){
if(root == null){
return "X,";
}
String left = serialize(root.left);
String right = serialize(root.right);
return root.val + "," + left + right;
}
//反序列化
public TreeNode deserialize(String data){
String[] nodes = data.split(",");
Queue<String> queue = new ArrayDeque<>(Arrays.asList(nodes));//队列用来存放列表形式的节点
return buildTree(queue);
}
public TreeNode buildTree(Queue<String> queue){
String value = queue.poll();
if(value.equals("X")){
return null;
}
TreeNode node = new TreeNode(Integer.parseInt(value));//将字符串转化成数字
node.left = buildTree(queue);
node.right = buildTree(queue);
return node;
}
}
方法二:BFS | 广度优先搜索
(1)序列化:
维护一个队列,初始让根节点入列,考察出列节点:
- 如果出列的节点是
null
,将符号"X"
推入res
数组。 - 如果出列的节点是数值,将节点值推入数组
res
,并将它的左右子节点入列。 - 子节点
null
也要入列,它对应"X"
,要被记录,只是它没有子节点可入列。 - 入列、出列…直到队列为空,就遍历完所有节点,
res
构建完毕,转成字符串就好。
(2)反序列化:
依然先转成list
数组,用一个指针 cur
从第二项开始扫描。
- 起初,用
list[0]
构建根节点,并让根节点入列。 - 节点出列,此时
cur
指向它的左子节点值,cur+1
指向它的右子节点值。 - 如果子节点值是数值,则创建节点,并认 出列 的父亲,同时自己也是父亲,入列。
- 如果子节点值为
"X"
,什么都不用做,因为出列的父亲的left
和right
本来就是null
可见,所有的真实节点都会在队列里走一遍,出列就带出儿子入列
java代码如下:
public class Codec {
// 序列化
public String serialize(TreeNode root) {
if (root == null) {
return "";
}
StringBuilder sb = new StringBuilder();
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
if (node == null) {
sb.append("X,");
} else {
sb.append(node.val + ",");
queue.offer(node.left);
queue.offer(node.right);
}
}
return sb.toString();
}
// 反序列化
public TreeNode deserialize(String data) {
if (data == "") {
return null;
}
Queue<String> nodes = new ArrayDeque<>(Arrays.asList(data.split(",")));
TreeNode root = new TreeNode(Integer.parseInt(nodes.poll()));
Queue<TreeNode> queue = new ArrayDeque<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
String left = nodes.poll();
String right = nodes.poll();
if (!left.equals("X")) {
node.left = new TreeNode(Integer.parseInt(left));
queue.add(node.left);
}
if (!right.equals("X")) {
node.right = new TreeNode(Integer.parseInt(right));
queue.add(node.right);
}
}
return root;
}
}