实际上这题比较难的就是要考虑清楚,序列化后的整棵树应该是什么形状。
我们应该让整个二叉树的 左节点或右节点为空的节点的空节点 也加入到序列化后的列表中;
这是为什么呢?你可以尝试着按这个思路试试,只要 左节点或右节点为空的节点的空节点 也加入序列化列表
我们在反序列化时就可以简单的判断当前节点的情况,来决定是否将其插入到树中。
序列化:
通过上面简单分析,我可以试试实现序列化,既然我们要添加左右空节点,那么它肯定是需要
和别的节点有所不同,我们用一个空节点的标识 ~
来标识,当然也可以用其他的标识,只要不与
题目中的节点可能的值冲突,并且我们用这个标识来创一个空节点(得益于js的弱类型),用于占位。
function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
}
const sign = '~'; // 空节点的标识
const node = new TreeNode(sign); // 创建一空占位的空节点
const delimiter = ','; // 这个分隔符只要与标识和数值不冲突即可
function Serialize(pRoot)
{
if(!pRoot) return ''
const queue = [pRoot];
const tree = [];
while(queue.length) {
const top = queue.shift();
// 占位空节点和真实的节点都需要加入到序列化列表中,用于反序列化
tree.push(top.val)
if(top === node) continue; // 占位的空节点我们并不对其扩展
if(top.left) { // 如果有左节点就扩展
queue.push(top.left);
} else {
queue.push(node); // 如果没有左节点说明它是末梢节点
}
if(top.right) { // 类似
queue.push(top.right);
} else {
queue.push(node);
}
}
// 之所以这里又加了个 ',' 用于方便反序列化,这样反序列化就无须知道字符串格式
// 只要拿到时用分隔符进行分割即可
return `${tree.join(delimiter)}${delimiter}`;
}
function Deserialize(s)
{
// write code here
if(!s) return null;
// 直接使用分割符进行分隔,按自己的规则生成树即可
s = s.split(delimiter);
const tree = new TreeNode(s[0]);
const queue = [tree];
for(let i = 1; i < s.length - 1; i += 2) {
const top = queue.shift();
const leftV = s[i];
const rightV = s[i + 1];
// 判断这是不是一个占位的值,如果不是就可以生成节点
if(leftV !== sign) {
top.left = new TreeNode(leftV);
// 生成完节点也需要将该节点加入到队列中,用于下次扩展
queue.push(top.left);
}
if(rightV !== sign) {
top.right = new TreeNode(rightV);
queue.push(top.right);
}
}
return tree;
}
module.exports = {
Serialize : Serialize,
Deserialize : Deserialize
};