题意
请实现两个函数,分别用来序列化和反序列化二叉树。
你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
解题思路
由题意可知,我们只需要保证将一颗二叉树序列化成字符串,然后可以通过这个字符串反序列化成以前的二叉树就行了。至于字符串的顺序,不做要求,因此我们既可以选择广度优先遍历也可以选择深度优先遍历 。上图中是广度优先遍历的结果。
对于本题,我使用深度优先搜索。
二叉树的序列化本质上是对其值进行编码,更重要的是对其结构进行编码。可以遍历树来完成上述任务。众所周知,我们一般有两个策略:广度优先搜索和深度优先搜索。
- 广度优先搜索可以按照层次的顺序从上到下遍历所有的节点
- 度优先搜索可以从一个根开始,一直延伸到某个叶,然后回到根,到达另一个分支。根据节点、左节点和右节点之间的相对顺序,可以进一步将深度优先搜索策略区分为:
- 先序遍历
- 中序遍历
- 后序遍历
这里,我们选择先序遍历的编码方式,我们可以通过这样一个例子简单理解 :
即我们可以先序遍历这颗二叉树,遇到空子树的时候序列化成 NULL
,否则继续递归序列化。
那么我们如何反序列化呢?首先我们需要根据 ' ,
'
把原先的序列分割开来得到先序遍历的元素列表,然后从左向右遍历这个序列:
- 如果当前的元素为
NULL
,则当前为空树 - 否则先解析这棵树的左子树,再解析它的右子树
C++实现
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec
{
public:
// 序列化二叉树,返回一个字符串
string serialize(TreeNode* root)
{
string res; // 存放结果
if(NULL==root)
return res;
_serialize(root,res);
return res;
}
void _serialize(TreeNode* node,string& str)
{
//先序遍历,首先处理根节点
// 如果当前遍历节点不为空,则将 该节点的值 送入 序列化结果str 中。
if(nullptr!=node)
{
str+=to_string(node->val)+',';
//下面两步只能放在当前 作用块 里面,因为只有当前节点不为空,才能继续处理当前节点的左右节点
_serialize(node->left,str); // 处理左节点
_serialize(node->right,str); // 处理右节点
}
else // 如果当前遍历的节点为空,将 NULL 送入str中
{
str+="NULL,";
}
}
// 反序列化二叉树,根据序列化的结果,返回二叉树的根节点
TreeNode* deserialize(string data)
{
if(data.empty())
return nullptr;
list<string> data_array;
string str;
// 首先解析 序列化结果的字符串,根据 ',' 进行分割
for(auto& ch:data)
{
if(ch!=',')
{
// 如果遍历的当前字符不是分割符',',则将该字符拼接到str中
str.push_back(ch);
}
else
{
//如果当前字符是分割符,则将str加入data_array中
data_array.push_back(str);
str.clear();//把string对象置为空。
}
}
if(!str.empty())
{
//谨防遗漏
data_array.push_back(str);
str.clear();
}
TreeNode* head = _deserialize(data_array);
return head;
}
TreeNode* _deserialize(list<string>& data_array)
{
TreeNode* head = nullptr;
//data_array中存放了 二叉树前序遍历 的结果
if(data_array.front()!="NULL")
{
int val = stoi(data_array.front()); //将 数字字符串 转为整数
data_array.pop_front(); //删除容器的第一个元素
head = new TreeNode(val);
}
else
{
//如果容器首元素是"NULL",直接返回空指针即可
data_array.pop_front();
return nullptr;
}
head->left=_deserialize(data_array);
head->right=_deserialize(data_array);
return head;
}
};