剑指offer61_序列化二叉树_题解
序列化二叉树
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
例如,我们可以把一个只有根节点为1的二叉树序列化为"1,",然后通过自己的函数来解析回这个二叉树
分析
方案一:层次遍历
序列化 Serialize
借助队列,对二叉树做层序遍历,并将越过叶节点的 \(null\) 也打印出来
算法流程:
- 初始化:序列化字符串 \(ret\) , 队列 \(q\) 初始时存放根节点 \(root\)
- 层序遍历:当 \(q\) 为空时跳出循环
- 获取二叉树每层的结点个数 \(sz\)
- 遍历每层的所有结点
- 获取头结点 \(top\)
- \(top\) 出队
- 判断 \(top\) 是否为空指针
- 如果为空,序列化字符串中添加 '#'
- 如果不为空,序列化字符串中添加 \(top\) 的节点值 \(top->val\),同时将 \(top\) 的左右孩子结点入队
- 返回值:通过 \(ret\) 转换得到的 \(C\) 序列化字符串 \(ans\)
反序列化 Deserialize
利用队列串按层构建二叉树
算法流程:
- 初始化:字符流 \(ss\) , 队列 \(q\) 初始时存放根节点 \(root\)
- 层序遍历:当 \(q\) 为空时跳出循环
- 获取二叉树每层的结点个数 \(sz\)
- 遍历每层的所有结点
- 获取头结点 \(top\)
- \(top\) 出队
- 判断 \(top\) 是否为空指针
- 如果为空,跳出循环遍历下一个结点
- 如果不为空, 调用 \(newNode\)函数新建左右孩子,并让 \(root\) 指向左右孩子,同时将左右孩子入队
- 返回根节点 \(root\)
代码
/*
1.时间复杂度:O(n)
2.空间复杂度:O(n)
*/
class Solution
{
public:
char *Serialize(TreeNode *root)
{
string ret = "";
queue<TreeNode *> q;
q.push(root);
while (!q.empty())
{
int sz = q.size();
while (sz--)
{
TreeNode *top = q.front();
q.pop();
if (top)
{
ret += to_string(top->val);
q.push(top->left);
q.push(top->right);
}
else
{
ret += "#";
}
ret += " ";
}
}
char *ans = new char[ret.length() + 1];
strcpy(ans, ret.c_str());
return ans;
}
TreeNode *newNode(string s)
{
TreeNode *Node;
if (s == "#")
Node = NULL;
else
Node = new TreeNode(stoi(s));
return Node;
}
TreeNode *Deserialize(char *str)
{
stringstream ss(str);
string s;
ss >> s;
queue<TreeNode *> q;
TreeNode *root = newNode(s);
q.push(root);
while (!q.empty())
{
int sz = q.size();
while (sz--)
{
TreeNode *top = q.front();
q.pop();
if (!top)
break;
ss >> s;
top->left = newNode(s);
q.push(top->left);
ss >> s;
top->right = newNode(s);
q.push(top->right);
}
}
return root;
}
};