遍历BFSDFS 二叉树的序列化与反序列化
题目
难度:困难
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
示例:
你可以将以下二叉树:
1
/ \
2 3
/ \
4 5
序列化为 "[1,2,3,null,null,4,5]"
解法一:dfs解法
深度优先搜索算法(Depth First Search,简称DFS)
1.解题
序列化:求二叉树的先序遍历序列 反序列化:通过序列化得到的先序遍历序列 构建原二叉树
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
StringBuilder res=mySeri(root,new StringBuilder());
return res.toString();
}
StringBuilder mySeri(TreeNode root,StringBuilder sb){
if(root==null){
sb.append("null,");
return sb;
}
else if(root!=null){
sb.append(root.val);
sb.append(",");
mySeri(root.left,sb);
mySeri(root.right,sb);
}
return sb;
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
String []temp=data.split(","); // 将序列化的结果转为字符串数组
List<String> list=new LinkedList<>(Arrays.asList(temp)); // 字符串数组转为集合类 便于操作
return myDeSeri(list);
}
public TreeNode myDeSeri(List<String> list){
TreeNode root;
if(list.get(0).equals("null")){
list.remove(0); // 删除第一个元素 则第二个元素成为新的首部 便于递归
return null;
}
else{
root=new TreeNode(Integer.valueOf(list.get(0)));
list.remove(0);
root.left=myDeSeri(list);
root.right=myDeSeri(list);
}
return root;
}
}
2.方法解释
1.spilt(); 拆分String为字符串数组 2.Arrays.asList();
(1)该方法不适用于基本数据类型(byte,short,int,long,float,double,boolean) (2)该方法将数组与列表链接起来,当更新其中之一时,另一个自动更新 (3)不支持add和remove方法 (1)该方法不适用于基本数据类型(byte,short,int,long,float,double,boolean) (2)该方法将数组与列表链接起来,当更新其中之一时,另一个自动更新 (3)不支持add和remove方法
解法二:bfs解法
BFS,其英文全称是Breadth First Search。 宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。
1.解法
序列化:通用bfs 反序列化:每次遍历2个节点 这2个节点是出队节点的左右孩子
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if(root==null){
return "";
}
StringBuilder res=new StringBuilder();
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode cur=queue.poll();
if(cur==null){
res.append("null,");
}
else{
res.append(String.valueOf(cur.val));
res.append(",");
queue.offer(cur.left);
queue.offer(cur.right);
}
}
return res.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if(data.equals("")){
return null;
}
String []temp=data.split(",");
TreeNode root=new TreeNode(Integer.valueOf(temp[0]));
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root);
TreeNode cur=root;
for(int i=1;i<temp.length;){
cur=queue.poll();
if(!temp[i].equals("null")){
cur.left=new TreeNode(Integer.valueOf(temp[i]));
queue.offer(cur.left);
}
i+=1;
if(!temp[i].equals("null")){
cur.right=new TreeNode(Integer.valueOf(temp[i]));
queue.offer(cur.right);
}
i+=1;
}
return root;
}
}
2.方法解析
1.offer(); 往队列尾部插入元素,如果超出边界则返回false
深度优先与广度优先的差异
稀疏图bfs会快于dfs,稠密图差不多。dfs写比较简单,bfs没有栈溢出风险
1.DFS:栈(先进后出) 走到尽头 步骤:
1.首先A入栈,
2、A出栈时,A的邻接结点B,C相应入栈 (这里假设C在下,B在上)
3.B出栈时,B的邻接结点A,C,D中未进过栈的D入栈
4.D出栈时,D的邻接结点B,C,E,F中未进过栈的E、F入栈(假设E在下,F在上)
5.F出栈时,F没有邻接结点可入栈
6.E出栈,E的邻接结点C,D已入过栈
7.C出栈
2.BFS: 队列(先进先出) 按照层次来遍历 步骤:
1.首先A入队列,
2.A出队列时,A的邻接结点B,C相应进入队列
3.B出队列时,B的邻接结点A,C,D中未进过队列的D进入队列
4.C出队列时,C的邻接结点A,B,D,E中未进过队列的E进入队列
5.D出队列时,D的邻接结点B,C,E,F中未进过队列的F进入队列
6.E出队列,没有结点可再进队列
7.F出队列