跳到主要内容

序列化与反序列化

为什么序列化必须显式编码空节点?​

  • 目的: 把树转成字符串以便存储或传输, 另一端还原成等价的树;
  • 关键: 只用节点值无法确定结构, 必须给空节点留一个不会与节点值冲突的标记;

前序序列化如何编码?​

  • 规则: 前序遍历输出节点值, 空节点输出占位标记, 用分隔符连接;
const serialize = function (root) {
const dfs = (node) => {
if (node == null) return "#";
return node.val + "," + dfs(node.left) + "," + dfs(node.right);
};

return dfs(root);
};

反序列化如何还原?​

  • 做法: 按分隔符切开, 依次消费 token; 遇到空标记返回 null, 否则先建根节点再递归建左右子树;
  • 依据: token 的消费顺序与序列化时的前序顺序一致;
const deserialize = function (data) {
const tokens = data.split(",");
const dfs = () => {
const value = tokens.shift();
if (value === "#") return null;
const node = new TreeNode(Number(value));
node.left = dfs();
node.right = dfs();
return node;
};

return dfs();
};

复杂度如何?​

  • 时间: O(n), 每个节点只处理一次;
  • 空间: O(n), 递归栈与 token 数组;
  • 其它口径: 层序序列化同样可行, 也必须编码空节点, 见 层序遍历;