一、题目描述:297. 二叉树的序列化与反序列化(困难)
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
示例:
你可以将以下二叉树:
1
/ \
2 3
/ \
4 5序列化为 "[1,2,3,null,null,4,5]"
提示: 这与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。说明: 不要使用类的成员 / 全局 / 静态变量来存储状态,你的序列化和反序列化算法应该是无状态的。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、解题思路
方法一、粗暴中序构造满二叉树法
1、序列化的时候按层序列化,将第一个元素入队,记录非null的元素个数coun = 1,进入循环,遍历队列,如果遇到null则push_back 两个null,如果遇到非null则入队左右子树节点,左子树非null,count++,右子树非null,count++。然后往右移一步,当前节点为非null则count--。直到count ==0.退出循环。
2、由于1构造了满二叉树,符合左右子树left = 2*index,right=2*index+1的特点,所以可以通过递归root->left = data[2*index +] root->data[2*index+1]构造二叉树
这种方法由于构造了满二叉树,导致存在很多非必要的null值,内存溢出
方法二、
1、按前序遍历将树序列化,遇到节点null则入栈,返回。每个节点通过”#“分割。
2、反序列化,先把string按”#“符合分割成vector,按照前序遍历的方式构造子树,每构造一个index往前走一步,遇到null则返回。直到index走到头。
三、代码
方法二、
/**
* 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:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
string save;
serializer(root,save);
return save;
}
void serializer(TreeNode* root,string & save) {
if(root == NULL)
{
save.append("null");
save.append("#");
return;
}
save.append(to_string(root->val));
save.append("#");
serializer(root->left,save);
serializer(root->right,save);
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
if(data.size() == 0)
return NULL;
int index = 0;
int pos = data.find("#",index);
vector<string> rdata;
while(pos > 0)
{
rdata.push_back(data.substr(index,pos-index));
index = pos + 1;
pos = data.find("#",index);
}
if(rdata.size() == 0)
return NULL;
if(rdata[0] == ",")
return NULL;
int index1 = 0;
//print(rdata);
TreeNode * root = NULL; //new TreeNode(atoi(rdata[0].c_str()));
rebuild1(&root,rdata,index1);
return root;
}
void rebuild1(TreeNode ** root,vector<string>& data,int & index)
{
if(index > data.size())
return;
if(data[index] == "null")
{
index++;
return;
}
(*root) = new TreeNode(atoi(data[index].c_str()));
index++;
rebuild1(&(*root)->left,data,index);
rebuild1(&(*root)->right,data,index);
}
void print(vector<string> & data)
{
for(int i = 0; i < data.size(); i++)
{
cout<<data[i]<<",";
}
cout<<endl;
}
};
// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
方法一
/**
* 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:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
vector<TreeNode *> save;
int count_left = 0;
if(root == NULL)
return "";
save.push_back(root);
if(root != NULL)
count_left ++;
int index = 0;
while(index < save.size())
{
//cout<<"index="<<index<<endl;
if(save[index] == NULL)
{
//save.push_back(NULL);
//save.push_back(NULL);
index++;
continue;
}
//cout<<"index="<<index<<endl;
if(save[index]->left != NULL)
count_left++;
if(save[index]->right != NULL)
count_left++;
save.push_back(save[index]->left);
save.push_back(save[index]->right);
count_left--;
index++;
if(count_left == 0)
break;
}
string serialize;
for(int i = 0; i< save.size();i ++)
{
if(save[i] == NULL)
{
serialize.append("null");
}
else
{
serialize.append(to_string(save[i]->val));
}
serialize.append("#");
}
//cout<<"serialize="<<serialize<<endl;
return serialize;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
if(data.size() == 0)
return NULL;
int index = 0;
int pos = data.find("#",index);
vector<string> rdata;
while(pos > 0)
{
rdata.push_back(data.substr(index,pos-index));
index = pos + 1;
pos = data.find("#",index);
}
if(rdata.size() == 0)
return NULL;
if(rdata[0] == ",")
return NULL;
int index1 = 0;
//print(rdata);
TreeNode * root = NULL; //new TreeNode(atoi(rdata[0].c_str()));
rebuild(&root,rdata,index1);
return root;
}
void print(vector<string> & data)
{
for(int i = 0; i < data.size(); i++)
{
cout<<data[i]<<",";
}
cout<<endl;
}
void rebuild(TreeNode ** root,vector<string> & rdata,int index)
{
int index_left = 2*(index+1)-1;
int index_right = 2*(index+1);
if(index_left < rdata.size() && rdata[index_left] != ",")
{
TreeNode * left = new TreeNode(atoi(rdata[index_left].c_str()));
(*root)->left = left;
rebuild(&left,rdata,index_left);
}
if(index_right < rdata.size() && rdata[index_right] != ",")
{
TreeNode * right = new TreeNode(atoi(rdata[index_right].c_str()));
(*root)->right = right;
rebuild(&right,rdata,index_right);
}
}
};
// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));