1 二叉树的序列化与反序列化
-
二叉树的序列化是指将二叉树转换为唯一标识的字符串,反序列化是指将字符串转换为相应的二叉树。
-
二叉树可以使用先序、中序、后序和层次遍历进行序列化,可以使用先序、后序和层次遍历进行反序列化。(中序遍历不可以反序列化)
-
如何判断两个二叉树相等?可能想法就是遍历二叉树,依次比较节点是否相等,这是没有问题的。但是如何判断子树中是否存在相等的树呢?可能就需要将所有子树序列化,加入一个map集合,从而进行判断。652 寻找重复的子树,就使用了这个思想,将在下一笔记中总结此题。
2 先序遍历解法
序列化,对于某一节点
-
若为
null,则在字符串中加入#来表示空树。 -
否则,在字符串中加入该值。
/* 前序二叉树序列化 */
private String preSerialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
preSerialize(root, sb);
return sb.toString();
}
/* 辅助函数,将二叉树存入StringBuilder */
private void preSerialize(TreeNode root, StringBuilder sb) {
if (root == null) {
sb.append("#").append(",");
return;
}
/* ---- 先序遍历代码 ---- */
sb.append(root.val).append(",");
/* ------------------- */
preSerialize(root.left, sb);
preSerialize(root.right, sb);
}
反序列化,先将字符串转换为nodes数组,利用数组中第一个元素为根节点这个性质,反序列化,建立二叉树。
/* 前序二叉树反序列化 */
private TreeNode preDeserialize(String data) {
Deque<String> nodes = new LinkedList<>();
for (String s : data.split(",")) {
nodes.addLast(s);
}
return preDeserialize(nodes);
}
private TreeNode preDeserialize(Deque<String> nodes) {
// base case
if (nodes.isEmpty()) {
return null;
}
/* ---- 先序遍历代码 ---- */
String node = nodes.removeFirst();
if (node.equals("#")) {
return null;
}
TreeNode root = new TreeNode(Integer.parseInt(node));
/* -------------------- */
root.left = preDeserialize(nodes);
root.right = preDeserialize(nodes);
return root;
}
3 中序遍历解法
序列化,其实与先序遍历思路一致,只是处理代码换了一个位置。
/* 中序遍历序列化 */
private String inSerialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
inSerialize(root, sb);
return sb.toString();
}
/* 辅助函数,将二叉树root序列化为StringBuilder */
private void inSerialize(TreeNode root, StringBuilder sb) {
if (root == null) {
sb.append("#").append(",");
return;
}
inSerialize(root.left, sb);
/* ---- 中序遍历代码 ---- */
sb.append(root.val).append(",");
/* ------------------- */
inSerialize(root.right, sb);
}
反序列化,由于从中序遍历数组中无法知道根节点的位置,所以无法进行反序列化。
4 后序遍历解法
序列化,与先序遍历思路基本一致。
/* 后序遍历序列化 */
private String postSerialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
postSerialize(root, sb);
return sb.toString();
}
/* 辅助函数,将二叉树root后序序列化为StringBuilder */
private void postSerialize(TreeNode root, StringBuilder sb) {
if (root == null) {
sb.append("#").append(",");
return;
}
postSerialize(root.left, sb);
postSerialize(root.right, sb);
/* ---- 后序遍历代码 ---- */
sb.append(root.val).append(",");
/* ------------------- */
}
反序列化,这里要注意,后序遍历数组中最后一个节点才是根节点,所以处理时应该先生成右子树,再生成左子树。
/* 后序遍历反序列化 */
private TreeNode postDeserialize(String data) {
LinkedList<String> nodes = new LinkedList<>();
for (String s : data.split(",")) {
nodes.addLast(s);
}
return postDeserialize(nodes);
}
/* 辅助函数,将LinkedList<String>后序反序列化为TreeNode */
private TreeNode postDeserialize(LinkedList<String> nodes) {
if (nodes.isEmpty()) {
return null;
}
String node = nodes.removeLast();
if (node.equals("#")) {
return null;
}
TreeNode root = new TreeNode(Integer.parseInt(node));
// 先构造右子树,再构造左子树
root.right = postDeserialize(nodes);
root.left = postDeserialize(nodes);
return root;
}
5 层次遍历解法
序列化,像BFS那样,使用一个结点队列,在while中依次出队
-
若为null,则在字符串后加上"#",并continue。
-
否则,在字符串后加上相应的值,然后在该节点的左右结点依次入队。
/* 层次遍历序列化 */
private String hierSerialize(TreeNode root) {
if (root == null) return "";
StringBuilder sb = new StringBuilder();
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
TreeNode cur = q.poll();
if (cur == null) {
sb.append("#").append(",");
continue;
}
sb.append(cur.val).append(",");
q.offer(cur.left);
q.offer(cur.right);
}
return sb.toString();
}
反序列化,使用层次遍历反向建立二叉树。
/* 层次遍历反序列化 */
private TreeNode hierDeserialize(String data) {
if (data.isEmpty()) return null;
String[] nodes = data.split(",");
// 第一个元素为root
TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));
// 队列q记录父节点,将root加入队列
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
int i = 1;
while(i < nodes.length) {
TreeNode parent = q.poll();
// 父节点对应左侧的节点
String left = nodes[i++];
if (!left.equals("#")) {
parent.left = new TreeNode(Integer.parseInt(left));
q.offer(parent.left);
} else {
parent.left = null;
}
// 父节点右侧的节点
String right = nodes[i++];
if (!right.equals("#")) {
parent.right = new TreeNode(Integer.parseInt(right));
q.offer(parent.right);
} else {
parent.right = null;
}
}
return root;
}
6 相关题目
本文介绍二叉树的序列化与反序列化方法,包括先序、中序、后序及层次遍历的序列化和反序列化过程,并提供了具体的实现代码。
528

被折叠的 条评论
为什么被折叠?



