当前位置:网站首页>leetcode:297. 二叉树的序列化与反序列化
leetcode:297. 二叉树的序列化与反序列化
2022-04-22 03:10:00 【OceanStar的学习笔记】
题目来源
题目描述
、

题目解析
二叉树序列化的本质是对其进行编码,更重要的是对其结构进行编码。可以遍历树来完成上述任务。一般有两个策略:广度优先搜索和深度优先搜索
- 广度优先搜索可以按照层次从上往下遍历所有节点
- 深度优先搜索可以从一个根节点开始,一直延伸到某个叶,然后回到根,到达另一个分支。根据根节点、左节点和右节点之间的相对顺序,可以进一步将深度优先搜索策略区分为:
- 先序遍历
- 中序遍历
- 后序遍历
深度优先搜索
序列化:
- 递归遍历一棵树,重点关注当前节点,它的子树的遍历交给递归完成:“serialize函数,请帮我分别序列化我的左右子树,我等你返回的结果,再拼接一下。”
- 选择前序遍历,是因为 根|左|右根∣左∣右 的打印顺序,在反序列化时更容易定位出根节点的值。
- 遇到 null 节点也要翻译成特定符号,反序列化时才知道这里是 null。

反序列化
- 前序遍历的序列化字符串,就像下图右一:

- 定义函数 buildTree 用于还原二叉树,传入由序列化字符串转成的 list 数组。
- 逐个 pop 出 list 的首项,构建当前子树的根节点,顺着 list,构建顺序是根节点,左子树,右子树。
- 如果弹出的字符为 “X”,则返回 null 节点。
- 如果弹出的字符是数值,则创建root节点,并递归构建root的左右子树,最后返回root。

class Codec {
static TreeNode *buildTree( std::list<std::string> & strList){
std::string strtmp = strList.front();
strList.pop_front();
if(strtmp == "X"){
return NULL;
}
TreeNode *node = new TreeNode(stoi(strtmp));
node->left = buildTree(strList);
node->right = buildTree(strList);
return node;
}
static std::list<std::string> split(std::string & data){
int len = data.size();
std::string curr;
std::list<std::string> dataArray;
for(char & ch : data){
if(ch == ','){
dataArray.push_back(curr);
curr.clear();
}else{
curr.push_back(ch);
}
}
if(!curr.empty()){
dataArray.push_back(curr);
curr.clear();
}
return dataArray;
}
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
if(root == NULL){
// 遍历到 null 节点
return "X";
}
std::string left = serialize(root->left);
std::string right = serialize(root->right);
return std::to_string(root->val) + "," + left + "," + right; // 按 根,左,右 拼接字符串
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
list<string> list = split(data);
TreeNode* res = buildTree(list);
return res;
}
};

struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {
}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {
}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {
}
};
class Codec {
void serialize(TreeNode *root, ostringstream &out) {
if(root){
out << root->val << ' ';
serialize(root->left, out);
serialize(root->right, out);
}else{
out << "# ";
}
}
TreeNode *deserialize(istringstream &in){
std::string val;
in >> val;
if(val == "#"){
return nullptr;
}
TreeNode *root = new TreeNode(stoi(val));
root->left = deserialize(in);
root->right = deserialize(in);
return root;
}
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
std::ostringstream out;
serialize(root, out);
return out.str();
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
std::istringstream in(data);
return deserialize(in);
}
};
广度优先搜索
序列化
- 维护一个队列,初始让根节点入队,考察出队节点:
- 如果出队的节点是NULL,将
x推入res - 如果出队的节点是数值,将节点值推入res,并将它的左右节点入队
- 子节点 null 也要入列,它对应 “X”,要被记录,只是它没有子节点可入列
- 如果出队的节点是NULL,将
- 入列、出列…直到队列为空,就遍历完所有节点,res构建完毕,转成字符串就好。
反序列化
下图是BFS得到的序列化字符串,和DFS得到的不同,它是一层层的。除了第一个是根节点的值,其他节点值都是成对的,对应左右子节点。

- 依然先转成list数组,用一个指针 cursor 从第二项开始扫描。
- 起初,用list[0]构建根节点,并让根节点入列
- 节点出列,此时 cursor 指向它的左子节点值,cursor+1 指向它的右子节点值。
- 如果子节点值是数值,则创建节点,并认出列的父亲,同时自己也是父亲,入列。
- 如果子节点值为 ‘X’,什么都不用做,因为出列的父亲的 left 和 right 本来就是 null
- 可见,所有的真实节点都会在队列里走一遍,出列就带出儿子入列

class Codec {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
std::ostringstream out;
std::queue<TreeNode*> q;
if(root){
q.push(root);
}
while (!q.empty()){
TreeNode *t = q.front(); q.pop();
if(t){
out << t->val << ' ';
q.push(t->left);
q.push(t->right);
}else{
out <<"# ";
}
}
return out.str();
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
if(data.empty()){
return nullptr;
}
std::istringstream in(data);
std::queue<TreeNode *>q;
std::string val;
in >> val;
TreeNode *res = new TreeNode(stoi(val)), *curr = res;
q.push(curr);
while (!q.empty()){
TreeNode *t = q.front(); q.pop();
if(!(in >> val)){
break;
}
if(val != "#"){
curr = new TreeNode(stoi(val));
q.push(curr);
t->left = curr;
}
if(!(in >> val)){
break;
}
if(val != "#"){
curr = new TreeNode(stoi(val));
q.push(curr);
t->right = curr;
}
}
return res;
}
};

版权声明
本文为[OceanStar的学习笔记]所创,转载请带上原文链接,感谢
https://blog.csdn.net/zhizhengguan/article/details/124334301
边栏推荐
- 职场礼仪.外企邮件怎么用
- Bad config encountered during initialization:/ No such notebook dir:
- Another perspective on the meta universe: the meta universe culture is quietly changing the world
- Wechat H5 payment (reporting cross domain issues)
- The interface needs to be forward compatible. If it is incompatible, open V2 interface
- 如何通过沟通激发开放性思维
- Driverless virtual simulation (14) -- traffic sign recognition in image processing 2
- 源代码加密产品指南
- 微信H5支付(报跨域问题)
- Sword finger offer special breakthrough version 93, longest Fibonacci series
猜你喜欢
随机推荐
微信H5支付(报跨域问题)
twenty-seven. Package (import)
Serviceworker cache and HTTP cache
Wordpress blog Building Guide
Stackoverflow:IActionContextAccessor Is Null
7、Request_ Response
Use zlib to compress and decompress the stream and judge whether it has been compressed
Kerberos authentication protocol
二十六.以主程序形式运行main
Who has the at instruction set of CDMA mobile phone? Even the strange problems encountered by the computer. [email protected]
824. 山羊拉丁文(字符串分割 + 字符串替代)
Extraction method of code reconstruction
Can I go to my account? Is it safe?
OneFlow 如何做静态图的算子对齐任务
Ros2 learning notes (V) -- Summary of common instructions for ros2 command line operation (I)
剑指offer 专项突破版 91、粉刷房子
Wechat jsapi payment method and error (the URL of the current page is not registered, and the payment verification signature fails)
Apple watch theme picture crawl!
Protocole d'authentification Kerberos
500错误,提交响应后无法转发







