可能性探究:我们可以想到的是只有一棵树按照某个序是唯一确定要给结构的情况才可能被序列化和反序列化,比如我们对于以下的二叉树可以找到它的先序、中序、后序如下:
根据它的先序和后序我们找不到任何其他可能的树,所以可以根据先序和后序去做序列化和反序列化,但是中序就不是那么可靠,我们可以发现中序不止这一种可能性,反例如下:
看这个树是不是和上面那个树的中序一致,但是他们并不是同一棵树,所以中序不能用来做序列化和反序列化
根据我们序列化和反序列化的相关知识,序列化和反序列化肯定都是一样的顺序
先序方式序列化,我们把结果放在数组里(也可以放在队列里)
[“1”, “2”,null, "3", null, null, "4", null,null]
下标 0 1 2 3 4 5 6 7 8
反序列化时根据这个数组的内容,遇到null代表左子树或者又子树已经结束
根据这个进行反序列化创建树我们可以得到:
(1)先消费0位置(1),这是整棵树的头节点
(2)再消费1位置(2),这个位置时左子树的头节点
(3)消费2位置,发现位置为空,说明2的左子树为空,2这棵树的左子树终结
(4)消费3位置(3),开始建2的右树,把它作为2的右树的头节点
(5)消费位置4,开始建3的左子树,发现位置为空,说明3的左子树为空
(6)消费位置5,开始建3的右子树,发现位置为空,说明3的右子树为空
(7)消费位置6,此时1的整棵左数已经建完,开始建1的右树,位置6处的值为4,作为1的右树的头节点
(8)消费位置7, 开始建立4的左子树,发现这个位置为空,所以4的左子树为空。
(9)消费位置8, 开始建立4的右子树,发现这个位置为空,所以4的右子树为空。
整个数组消费完毕,反序列化结束,我们反序列化简历的树如下
代码使用Queue代替数组实现
后序遍历序列化和反序列化跟先序的类似就不写了
下面分析层序遍历的序列化和反序列化,还是分析这棵树
ans中的值最终依次为"1" "2" "4" null "3" null null null null
反序列化的过程和序列化类似:
(1)先取出序列化结果的第一个元素,然后建立Node作为头节点,入队(新建立的用于遍历的队列)
(2)如果队列不为空,弹出一个节点,并弹出序列化结果中的下面两项作为它的左子节点和右子节点,如果左右子节点有不为空的加入队列(先左后右)
(3)重复2的步骤,直到队列为空
先序、层序序列化和反序列化代码如下:
package dataStructure.binaryTree;
import dataStructure.TreeNode;
import java.util.LinkedList;
import java.util.Queue;
public class SerializeAndDeSerialize {
public static void main(String[] args) {
TreeNode t1 = new TreeNode(1);
TreeNode t2 = new TreeNode(2);
TreeNode t3 = new TreeNode(3);
TreeNode t4 = new TreeNode(4);
t1.left = t2;
t1.right = t4;
t2.right = t3;
Queue<String> queue = preSerialize(t1);
//printQueue(queue);
TreeNode head = preDeSerialize(queue);
// System.out.println(head);
Queue<String> levelQueue = levelSerialize(t1);
//printQueue(levelQueue);
TreeNode head2 = levelDeSerialize(levelQueue);
System.out.println(head2);
}
private static void printQueue(Queue<String> queue) {
if(queue == null || queue.size() == 0) {
return;
}
/* while(!queue.isEmpty()) {
System.out.println(queue.poll());
}*/
queue.stream().forEach((x)-> System.out.println(x));
}
public static Queue<String> preSerialize(TreeNode head) {
Queue<String> queue = new LinkedList<>();
pres(head, queue);
return queue;
}
private static void pres(TreeNode head, Queue<String> queue) {
if(head == null) {
queue.add(null);
} else {
queue.add(String.valueOf(head.value));
pres(head.left, queue);
pres(head.right, queue);
}
}
public static TreeNode preDeSerialize(Queue<String> queue) {
if(queue == null) {
return null;
}
//消费一个位置
String value = queue.poll();
if(value == null) {
return null;
}
TreeNode head = new TreeNode(Integer.parseInt(value));
//对于每个被消费位置的元素再消费两个位置
//左子树的根节点消费一个
head.left = preDeSerialize(queue);
//右子树的根节点消费一个
head.right = preDeSerialize(queue);
//返回新建的树的根
return head;
}
public static Queue<String> levelSerialize(TreeNode head) {
if(head == null) return null;
Queue<String> ans = new LinkedList<>();
Queue<TreeNode> queue = new LinkedList<>();
ans.add(String.valueOf(head.value));
queue.add(head);
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
//只有不为空才加入queue
if(node.left != null) {
queue.add(node.left);
}
//不管是不是null都要加入ans中,注意判空
ans.add(node.left == null ? null : String.valueOf(node.left.value));
//只有不为空才加入queue
if(node.right != null) {
queue.add(node.right);
}
ans.add(node.right == null ? null : String.valueOf(node.right.value));
}
return ans;
}
public static TreeNode levelDeSerialize(Queue<String> queue) {
if(queue == null || queue.size() == 0) {
return null;
}
Queue<TreeNode> nodeQueue = new LinkedList<>();
TreeNode head = new TreeNode(Integer.parseInt(queue.poll()));
nodeQueue.add(head);
while(!nodeQueue.isEmpty()) {
TreeNode node = nodeQueue.poll();
String next = queue.poll();
node.left = next == null ? null : new TreeNode(Integer.parseInt(next));
next = queue.poll();
node.right = next == null ? null : new TreeNode(Integer.parseInt(next));
if(node.left != null) {
nodeQueue.add(node.left);
}
if(node.right != null) {
nodeQueue.add(node.right);
}
}
return head;
}
}
欢迎批评指正