系列文章目录
前言
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。
描述
请实现两个函数,分别用来序列化和反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。
二叉树的序列化(Serialize)是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树等遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#)
二叉树的反序列化(Deserialize)是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
例如,可以根据层序遍历的方案序列化,如下图:
层序序列化(即用函数Serialize转化)如上的二叉树转为"{1,2,3,#,#,6,7}“,再能够调用反序列化(Deserialize)将”{1,2,3,#,#,6,7}"构造成如上的二叉树。
当然你也可以根据满二叉树结点位置的标号规律来序列化,还可以根据先序遍历和中序遍历的结果来序列化。不对序列化之后的字符串进行约束,所以欢迎各种奇思妙想。
public class Codec {
int INF = 0x3f3f3f3f;
TreeNode emptyNode = new TreeNode(INF);
public String serialize(TreeNode root) {
if (root == null) return "";
StringBuilder sb = new StringBuilder();
// 使用队列进行层序遍历,起始先将 root 放入队列
Deque<TreeNode> d = new ArrayDeque<>();
d.addLast(root);
while (!d.isEmpty()) {
// 每次从队列中取出元素进行「拼接」,包括「正常节点」和「叶子节点对应的首位空节点」
TreeNode poll = d.pollFirst();
sb.append(poll.val + "_");
// 如果取出的节点不为「占位节点」,则继续往下拓展,同时防止「占位节点」不继续往下拓展
if (!poll.equals(emptyNode)) {
d.addLast(poll.left != null ? poll.left : emptyNode);
d.addLast(poll.right != null ? poll.right : emptyNode);
}
}
return sb.toString();
}
public TreeNode deserialize(String data) {
if (data.equals("")) return null;
// 根据分隔符进行分割
String[] ss = data.split("_");
int n = ss.length;
// 怎么序列化就怎么反序列化
// 使用队列进行层序遍历,起始先将 root 构建出来,并放入队列
TreeNode root = new TreeNode(Integer.parseInt(ss[0]));
Deque<TreeNode> d = new ArrayDeque<>();
d.addLast(root);
for (int i = 1; i < n - 1; i += 2) {
TreeNode poll = d.pollFirst();
// 每次从中取出左右节点对应 val
int a = Integer.parseInt(ss[i]), b = Integer.parseInt(ss[i + 1]);
// 如果左节点对应的值不是 INF,则构建「真实节点」
if (a != INF) {
poll.left = new TreeNode(a);
d.addLast(poll.left);
}
// 如果右节点对应的值不是 INF,则构建「真实节点」
if (b != INF) {
poll.right = new TreeNode(b);
d.addLast(poll.right);
}
}
return root;
}
}