此题力扣序号为297,看题解前最好看仔细看一下题目以及结构要求
题目为 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
这里需要对二叉树遍历进行介绍,二叉树的遍历主要分为两种。
- DFS(Depth First Search)
DFS(Depth First Search),深度优先搜索,深度优先搜索的概念定义是
深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法。
沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。
深度优先搜索,我个人的理解就是搜寻一个节点a,找到该a的一个子节点b,对子节点b找到一个b的子节点c,待遍历完成孙子节点c,重新返回到b,遍历b其他的子节点。遍历完b所有的节点后,返回a,遍历a其他的节点。也就是一直走一条路,走到头,再回头。
- BFS(Breath First Search)
BFS(Breath First Search)广度优先搜索,广度优先搜索的概念定义是
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
广度优先搜索,是按照层次顺序,去进行节点搜索,由上到下进行搜索树形结构。
下面是题解二叉树代码
根据题意就可以看出,使用的是广度优先遍历,但我先给出深度遍历算法的代码结构。
力扣给出的属性结构代码为
public class TreeNode
{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) { val = x; }
}
深度优先遍历代码
每个树都对应左右两个节点,节点可以为null。
深度遍历我主要使用的是递归,serialize方法是将TreeNode转换成字符串,deserialize是将字符串转换成TreeNode。
public TreeNode deserialize(string data)
{
List<string> liAll = data.Split(',').ToList();
return AllTree(liAll);
}
public TreeNode AllTree(List<string> liAll)
{
if (liAll == null || liAll.Count == 0)
{
return null;
}
if (liAll[0] == "null")
{
liAll.RemoveAt(0);
return null;
}
int.TryParse(liAll[0], out int res);
//生成当前节点,用完一个元素就将该元素从list移除
TreeNode tree = new TreeNode(res);
liAll.RemoveAt(0);
//递归生成左节点
tree.left = AllTree(liAll);
tree.right = AllTree(liAll);
return tree;
}
public string serialize(TreeNode root)
{
if (root == null)
{
return "null";
}
//递归左节点,相当于对左节点进行深度遍历
string left = serialize(root.left);
//右节点递归
string right = serialize(root.right);
return root.val + "," + left + right;
}
广度优先搜索
主要使用的是队列queue,先进先出,
序列化主要是先拼接添加加左侧节点,然后再拼接右侧节点。一直遍历到队列为空时结束。
反序列化是将的string结构为 1,2,3,null,null,4,5
对应图形为
当为Null,就跳过,继续遍历整个字符串。先添加左节点,再添加右节点,队列中添加顺序也是相同,然后取队列最先添加元素。在该元素下再继续添加元素。
public String serialize(TreeNode root)
{
if (root==null)
{
return "";
}
StringBuilder sb = new StringBuilder();
Queue<TreeNode> q = new Queue<TreeNode>();
q.Enqueue(root);
while (q.Count>0)
{
TreeNode tTemp = q.Dequeue();
if (tTemp==null)
{
sb.Append("null,");
}
else
{
sb.Append(tTemp.val+",");
q.Enqueue(tTemp.left);
q.Enqueue(tTemp.right);
}
}
return sb.ToString();
}
public TreeNode deserialize(String data)
{
if (string.IsNullOrEmpty(data))
{
return null;
}
List<string> li = data.Split(',').ToList();
Queue<TreeNode> q = new Queue<TreeNode>();
int.TryParse(li[0].Trim(), out int num1);
TreeNode treeRoot = new TreeNode(num1);
q.Enqueue(treeRoot);
TreeNode cur = treeRoot;
for (int i = 1; i < li.Count-1;)
{
cur = q.Dequeue();
if ( li[i].Trim()!="null")
{
bool res1= int.TryParse(li[i].Trim(), out int temp1);
if (res1)
{
cur.left = new TreeNode(temp1);
q.Enqueue(cur.left);
}
}
i += 1;
if (li[i].Trim() != "null")
{
bool res2 = int.TryParse(li[i].Trim(), out int temp2);
if (res2)
{
cur.right = new TreeNode(temp2);
q.Enqueue(cur.right);
}
}
i += 1;
}
return treeRoot;
}