二叉树的序列化和反序列化

二叉树被记录成文件的过程,叫做二叉树的序列化,通过文件内容重建原来二叉树的过程叫做二叉树的反序列化。
给定一棵二叉树的头节点head,并已知二叉树节点值的类型为32位整型。
请设计一种二叉树序列化和反序列化的方案并用代码实现。

应用:判断两颗二叉树中是否有子树完全相同,先序列化为文件,然后kmp

思路

将每个树的节点的值放在字符串中,用一个分隔符分开来,不然会引起歧义,然后将空节点也用特殊符号代替
本题用!代表分隔符,用#表示空结点
思路就是先序遍历和层次遍历,注意处理过程稍有不同

先序序列化及反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 先序序列化
//类似于树的先序遍历
public static String serialByPre(Node head) {
if (head == null) {
return "#!";
}
//处理根节点,然后左右节点
String res = head.value + "!";
res += serialByPre(head.left);
res += serialByPre(head.right);
return res;
}
// 先序反序列化
public static Node reconByPreString(String preStr) {
//分割字符串
String[] values = preStr.split("!");
//将字符添加到队列中
Queue<String> preQueue = new LinkedList<String>();
for (int i = 0; i < values.length; i++) {
preQueue.add(values[i]);
}
//还原树
return reconPreOrder(preQueue);
}
//还原树的过程类似于树的先序遍历
public static Node reconPreOrder(Queue<String> queue) {
//得到队头结点
String string = queue.poll();
if(string.equals("#")){
return null;
}
//处理根节点
Node head = new Node(Integer.valueOf(string));
//处理左右节点
head.left = reconPreOrder(queue);
head.right = reconPreOrder(queue);
return head;
}

层次序列化及反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// 层次序列化
public static String serialByLevel(Node head) {
if (head == null) {
return "#!";
}
Queue<Node> queue = new LinkedList<Node>();
// 头结点入队处理,而不出队时处理
// 因为这里对于空节点也要处理
String res = Integer.valueOf(head.value) + "!";
queue.add(head);
while (!queue.isEmpty()) {
Node node = queue.poll();
// 入队时处理左右节点,因为有空节点
if (node.left != null) {
res += Integer.valueOf(node.left.value) + "!";
queue.add(node.left);
} else {
// 空结点也要处理
res += "#!";
}
if (node.right != null) {
res += Integer.valueOf(node.right.value) + "!";
queue.add(node.right);
} else {
res += "#!";
}
}
return res;
}
public static Node reconByLevelString(String levelStr) {
String[] strings = levelStr.split("!");
//与层次遍历相似
Queue<Node> queue = new LinkedList<Node>();
int index = 0;
//处理头结点并入队
Node head = generateNodeByString(strings[index++]);
//不空才入队
if(head != null){
queue.add(head);
}
while(!queue.isEmpty()){
//出队头
Node node = queue.poll();
//处理左结点,并入队
node.left = generateNodeByString(strings[index++]);
if(node.left != null){
queue.add(node.left);
}
//处理右结点,并入队
node.right = generateNodeByString(strings[index++]);
if(node.right != null){
queue.add(node.right);
}
}
return head;
}
// 根据value返回node
public static Node generateNodeByString(String val) {
if (val.equals("#")) {
return null;
}
return new Node(Integer.valueOf(val));
}