题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
思路
1.两个主函数分别调用两个实现序列化和反序列化的函数,序列化实现后将str序列元素逐个放入题干要求类型的数组array之中并返回结果;反序列化实现后返回二叉树根节点指针.
2.序列化实现:(选用先序遍历方式)
(1)只要传入的节点非空,则将该节点的数值转化为字符类型并添加至str中,再添加分隔的","
(2)递归调用本身函数判断左子节点,递归调用本身函数判断右子节点
3.反序列化实现:
(1)判断是否到达叶节点,如果达到叶节点,str指针后移一位并退出当前函数,返回上层递归;如果未到达叶节点,判断当前字符不是分隔符"!"且不是结束符"\0"时,则完整读取该字符并转换成数值类型放入当前树的节点root中,再判断是分隔符还是结束符以决定后移游标还是停止函数.并递归调用本身函数找到左子节点和右子节点.
(2)返回重建后二叉树的根节点
注意:
1.尽量用nullptr(新标准下C++程序),NULL为过去的程序中用到的预处理变量来给指针赋值
2.C++ Primer P188
指针形参(地址传递):定义函数时形如void reset( int *ip); 调用函数时reset(&i)
引用形参:定义函数时形如void reset(int &i); 调用函数时reset(j)
3.序列化二叉树时,不需要改变原树指针的指向,因此函数参数类型为指针;
反序列化二叉树时,需要按照序列构建二叉树,每次都不断改变新节点左右指针域的指向,因此函数参数类型为二级指针
代码
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
char* Serialize(TreeNode *root) {
//判断有效性
if(root == nullptr)
return nullptr;
//声明一个字符串存放树的节点元素
string str;
mySerialize(root, str);
//声明一个字符数组存放序列化结果
char* array = new char[str.size() + 1];
//将字符串逐个置入字符容器中
for(int i = 0; i < str.size() ; ++i)
{
array[i] = str[i];
}
//存放结束字符
array[str.size()] = '\0';
return array;
}
TreeNode* Deserialize(char *str) {
//判断有效性
if(str == nullptr)
return nullptr;
TreeNode* pStr = myDeserialize(&str);
return pStr;
}
private:
//序列化二叉树
void mySerialize(TreeNode* root, string& str)
{
//递归终止条件,到达叶节点时
if(root == nullptr)
{
str += '#';
return;
}
//树有节点存在
//将节点值转化为string类型存入str;
string node = to_string(root->val);
str += node;
str += '!';
//递归左右子树
mySerialize(root->left, str);
mySerialize(root->right, str);
}
//反序列化二叉树
TreeNode* myDeserialize(char** str)
{
//遍历至空节点时(叶节点)
if(**str == '#')
{
//指针后移一位
(*str)++;
return nullptr;
}
//声明一个数字用于存放当前节点转换后的数字
int number = 0;
//将当前扫描到的字符串转为数字
while(**str != '\0' && **str != '!')
{
number = number * 10 + ((**str) - '0');
//游标后移,判断是否将该字符串存储完毕
(*str)++;
}
//声明反序列化后二叉树的根节点并存入数据
TreeNode* pRoot = new TreeNode(number);
//判断退出循环的原因是因为字符串结束还是因为当前字符为!
if(**str == '\0')
return pRoot;
else
//整个字符串未扫描完,游标后移
(*str)++;
//重建该节点的左右子树
pRoot->left = myDeserialize(str);
pRoot->right = myDeserialize(str);
//返回重建二叉树的根节点
return pRoot;
}
};