1、题目描述
- 请实现两个函数,分别用来序列化和反序列化二叉树。
- 你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
- 提示:输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。
示例:
输入:root = [1,2,3,null,null,4,5]
输出:[1,2,3,null,null,4,5]
2、VS2019上运行
方法一:使用深度优先搜索
#include <iostream>
#include <cstring>
#include <string>
#include <list>
using namespace std;
// 二叉树节点的定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
// 序列化和反序列化二叉树的类
class Codec {
public:
// 辅助函数:序列化二叉树
void rserialize(TreeNode* root, string& str) {
if (root == nullptr) {
str += "None,"; // 空节点用"None"表示
}
else {
str += to_string(root->val) + ","; // 将节点值转化为字符串,并添加到str中
rserialize(root->left, str); // 递归序列化左子树
rserialize(root->right, str); // 递归序列化右子树
}
}
// 序列化二叉树,并返回序列化后的字符串
string serialize(TreeNode* root) {
string ret;//存储序列化后的二叉树字符串的结果
rserialize(root, ret);
return ret;
}
// 辅助函数:反序列化二叉树
TreeNode* rdeserialize(list<string>& dataArray) {
//处理空节点,确保在处理当前节点的值后,链表中的下一个元素就是下一个节点的值。
if (dataArray.front() == "None") {
dataArray.erase(dataArray.begin());
return nullptr; // 空节点返回nullptr
}
TreeNode* root = new TreeNode(stoi(dataArray.front())); // 创建当前节点
//stoi用于将第一个元素的字符串表示转换为整数值
dataArray.erase(dataArray.begin());
root->left = rdeserialize(dataArray); // 递归反序列化左子树
root->right = rdeserialize(dataArray); // 递归反序列化右子树
return root;
}
// 从输入字符串中反序列化二叉树,并返回根节点
TreeNode* deserialize(string data) {
list<string> dataArray;//存储从序列化字符串中解析出的节点值
string str;//临时存储当前节点的值
for (auto& ch : data) {//遍历序列化字符串 data 中的每个字符 ch
//如果当前字符 ch 是逗号 ‘,’,则表示当前节点值的结束。
//此时,将当前的节点值 str 存储到 dataArray 链表中,并清空 str 以准备解析下一个节点的值。
if (ch == ',') {
dataArray.push_back(str); // 用逗号分割字符串,并将每个节点值存储在链表中
str.clear();
}
else {
str.push_back(ch); // 构建当前节点的值
}
}
//处理最后一个节点值
if (!str.empty()) {
dataArray.push_back(str); // 将最后一个节点的值存储在链表中
str.clear();
}
return rdeserialize(dataArray);
}
};
// 测试序列化和反序列化函数
int main() {
// 创建一个二叉树
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->right->left = new TreeNode(4);
root->right->right = new TreeNode(5);
// 创建Codec类的实例
Codec codec;
// 序列化二叉树
string serialized = codec.serialize(root);
cout << "序列化后的二叉树字符串: " << serialized << endl;
// 反序列化二叉树
TreeNode* deserialized = codec.deserialize(serialized);
// 打印反序列化后的二叉树节点的值
if (deserialized != nullptr) {
cout << "反序列化后的二叉树节点值: " << endl;
cout << deserialized->val << endl;
cout << deserialized->left->val << " " << deserialized->right->val << endl;
cout << deserialized->right->left->val << " " << deserialized->right->right->val << endl;
}
else {
cout << "反序列化后的二叉树为空" << endl;
}
// 释放分配的内存,清理二叉树
delete root->right->left;
delete root->right->right;
delete root->left;
delete root->right;
delete root;
return 0;
}
序列化后的二叉树字符串: 1,2,None,None,3,4,None,None,5,None,None,
反序列化后的二叉树节点值:
1
2 3
4 5
3、解题思路
- 序列化:
1.serialize 函数接受一个二叉树的根节点 root,将二叉树转换为一个字符串。
2.rserialize 函数是一个递归函数,用于遍历二叉树。它首先将当前节点的值加入到字符串 str 中,如果当前节点为空,则将字符串 “None” 加入到 str 中;否则,将当前节点的左子树和右子树递归地进行序列化。
3.最后,serialize 函数返回生成的字符串 ret,即二叉树的序列化结果。 - 反序列化:
1.deserialize 函数接受一个字符串 data,将其转换为二叉树。
2.rdeserialize 函数是一个递归函数,用于重构二叉树。它首先检查当前节点值是否为 “None”,如果是则返回空指针;否则,创建一个新的节点,将节点值赋给它,并递归地构建左子树和右子树。
3.deserialize 函数首先将输入字符串 data 按照逗号进行拆分,构成一个字符串链表 dataArray。然后,调用 rdeserialize 函数,并将 dataArray 作为参数传入,来重建二叉树。
4.最后,deserialize 函数返回重建的二叉树的根节点。 - 通过 serialize 函数可以将二叉树转换为字符串,而 deserialize 函数可以将字符串恢复为原始的二叉树结构。
4、序列化和反序列化
- 序列化:将二叉树在内存中的表示形式转换为字符串
- 反序列化:将字符串还原为二叉树的内存表示形式