二叉树的序列化与反序列化
题目来源:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/ .
按照 Leetcode 的官方习惯,二叉树的序列化逻辑是根据其「层次遍历」序列来实现的(参考该文章),因此本文以这种方式来解题。
预备工作
对于反序列化过程,其输入是一个字符串,我们需要将其转换为 vector<string>
,如 "1,null,2"
需要转换为 {"1", "null", 2"}
.
vector<string> split(string &data, const string &sep)
{
size_t l = 0;
size_t r = data.find(sep, l);
vector<string> result;
while (r != string::npos)
{
result.emplace_back(data.substr(l, r - l));
l = r + sep.length();
r = data.find(sep, l);
}
if (l < data.length())
result.emplace_back(data.substr(l));
return result;
}
对于 vector<string>
中的每个元素,构造一个 API,返回对应的二叉树节点(包括空节点):
TreeNode *generateNode(const string &s)
{
return s == NIL ? nullptr : new TreeNode(stoi(s));
}
其次,需要 2 个常量(以成员变量的形式存在),NIL
是空节点的符号表示,SEPARATOR
是序列化字符串中的分隔符:
const string NIL = "null";
const string SEPARATOR = ",";
层次遍历实现
- 序列化
与一般的层次遍历几乎一样,唯一不同的地方是:在此处,空节点 nullptr
也进入队列当中 。
❗ 需要注意的是:最后一层均为叶子节点,因此它们的左右孩子均为 null
,按照 Leetcode 的要求,序列化字符串中不包含这些最后一层叶子节点的孩子。
string levelSerialize(TreeNode *root)
{
if (root == nullptr)
return "";
queue<TreeNode *> q;
q.push(root);
vector<string> result;
while (!q.empty())
{
auto node = q.front();
q.pop();
if (node != nullptr)
{
result.emplace_back(to_string(node->val));
q.push(node->left);
q.push(node->right);
}
else
result.emplace_back(NIL);
}
while (result.back() == NIL) result.pop_back();
string str;
for (auto &x : result) str += (x + SEPARATOR);
if (str.back() == SEPARATOR[0]) str.pop_back();
return "[" + str + "]";
}
- 反序列化
还是是普通的层次遍历算法改过来的~
TreeNode *levelDeserialize(string &data)
{
if (data.empty()) return nullptr;
if (data.front() == '[' && data.back() == ']') data = data.substr(1, data.length() - 2);
auto v = split(data, SEPARATOR);
int idx = 0, size = v.size();
auto root = generateNode(v[idx++]);
assert(root != nullptr);
queue<TreeNode *> q;
q.push(root);
while (!q.empty())
{
auto node = q.front();
q.pop();
if (idx < size) node->left = generateNode(v[idx++]);
if (idx < size) node->right = generateNode(v[idx++]);
if (node->left != nullptr) q.push(node->left);
if (node->right != nullptr) q.push(node->right);
}
return root;
}