声明:本文原题主要来自力扣,记录此博客主要是为自己学习总结,不做任何商业等活动!

一、下面是原题描述

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

提示: 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

示例 1:

输入:root = [1,2,3,null,null,4,5]
输出:[1,2,3,null,null,4,5]
示例 2:

输入:root = []
输出:[]
示例 3:

输入:root = [1]
输出:[1]
示例 4:

输入:root = [1,2]
输出:[1,2]

1.1 解题思路

前面已经学过二叉树的前序、中序、后续、层次遍历方式,但是这种遍历的输出是没有记录空节点的,依据这种输出无法完全唯一的还原原始二叉树,故需要遍历的时候将为null的叶子结点也保存起来。

如下图所示,原始输入是 root = [1,2,3,null,null,4,5],输出为:[1,2,3,null,null,4,5],即保存了为空的节点,包括叶子结点的左右子节点(null);即每个节点都有左右子节点,如果按照一定顺序存储,则可以用该顺序进行还原。下面采用的是层次遍历方法进行存储和还原。

根据题目示意,层次遍历方式是最直观理解和解题。

总体解题思想为先用层次遍历存储包括空节点的每个节点,存储是每个节点都存储左右子节点,如果节点为空,则存储"#,",否则存储节点的值val,同时用逗号','分割每个节点内容,存储完后进行序列化string。反序列化则先按逗号','分割每个字符串为数组字符串vector<string> valStrArr,该valStrArr存储每个节点的值,包括空节点;然后遍历valStrArr,反向构建原始二叉树。反向构建二叉树时由于存储是按层次遍历存入的,所以反向遍历时也需要按照层次遍历依次将非空节点压栈和弹出栈。由于层次遍历存储特性可知,第一个节点必定是根节点,后面两个必定是左右子节点,再后面两个是另一个非空子树的左右节点,后面紧挨着的两个节点依次是另外前面顺序入栈的非空节点的左右子节点。下面是具体解题步骤。

1.2 具体实现步骤

知道了解题思路,接下来是构建代码框架。

a1 序列化函数string serialize(TreeNode* root)是入参为根节点,返回字符串srting。序列化时按二叉树层次遍历存储每个节点,当为空时存储内容不是val而是'#',如下代码所示

string serialize(TreeNode* root) {if (root == nullptr)return "#";string result;std::queue<TreeNode*> nodeQueue;TreeNode* cur = nullptr;int isValid = false;int size = 0;nodeQueue.push(root);while (!nodeQueue.empty()) // 正常的层次遍历{size = nodeQueue.size();for (int i = 0; i < size; ++i){cur = nodeQueue.front();nodeQueue.pop();if (cur == nullptr) // 这里有区别,如果是空节点则存储为'#'{result.append("#,");continue;}result.append(std::to_string(cur->val) + ","); // 存储节点信息nodeQueue.push(cur->left); //这里有区别,不管是否空节点都压入栈nodeQueue.push(cur->right); //这里有区别,不管是否空节点都压入栈}}return result;}

a2 反序列化函数TreeNode* deserialize(string data),先将输入字符串分割为一个数组字符串,该数组字符串每个元素顺序存储按层次遍历的每个节点信息,代码如下

void toStrArr(const string& data, vector<string>& valsStr)
{string valStr;valStr.reserve(10); // 优化,预分配10个bytefor (const char& ch : data){if (ch == ','){valsStr.push_back(valStr); // 将每个节点的值存入数组valStr.clear(); // 初始化}else{valStr.push_back(ch); // 存储每个节点的值}}
}

a3 字符串转为存储每个节点信息的数组字符串后先将根节点压入队列,然后从下标为1开始遍历该数组字符串,每次遍历访问连续的两个节点(因为连续挨着的两个节点是上一个非空节点的左右子节点),并且判断非空则将该左右节点压入栈,然后再下一个循环中弹出一个节点进行挂接该节点的左右子节点,直到整个循环结束为止。

TreeNode* deserialize(string data) {if (data.compare("#") == 0) // 如果整个字符串为空,则直接返回nullptrreturn nullptr;vector<string> valsStr; // 数组字符串存储每个节点信息toStrArr(data, valsStr); // 将string转为数组字符串int size = valsStr.size();TreeNode* root = new TreeNode(std::stod(valsStr[0]));TreeNode* parent = nullptr;std::queue<TreeNode*> nodeQueue;nodeQueue.push(root); // 将根节点压入栈for (int i = 1; i < size; ++i){parent = nodeQueue.front();nodeQueue.pop();if (valsStr[i].compare("#")){parent->left = new TreeNode(std::stod(valsStr[i])); // 创建该节点左子节点nodeQueue.push(parent->left); // 非空则压入栈,顺序访问每个节点}if (valsStr[++i].compare("#")){parent->right = new TreeNode(std::stod(valsStr[i])); // 创建该节点右子节点nodeQueue.push(parent->right); // 非空则压入栈,顺序访问每个节点}}return root; // 返回原始二叉树
}

1.3 完整代码

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Codec {
public:/*解题思路:1.序列比:将所有节点的val(包括空节点)按照层次遍历存储到string,空节点存入null,用逗号','隔开2.反序列化:将string每个元素分解成stringArr存储每个元素,然后遍历*/// Encodes a tree to a single string.string serialize(TreeNode* root){if (root == nullptr)return "#";string result;std::queue<TreeNode*> nodeQueue;TreeNode* cur = nullptr;int isValid = false;int size = 0;nodeQueue.push(root);while (!nodeQueue.empty()) // 正常的层次遍历{size = nodeQueue.size();for (int i = 0; i < size; ++i){cur = nodeQueue.front();nodeQueue.pop();if (cur == nullptr) // 这里有区别,如果是空节点则存储为'#'{result.append("#,");continue;}result.append(std::to_string(cur->val) + ","); // 存储节点信息nodeQueue.push(cur->left); //这里有区别,不管是否空节点都压入栈nodeQueue.push(cur->right); //这里有区别,不管是否空节点都压入栈}}return result;}void toStrArr(const string& data, vector<string>& valsStr){string valStr;valStr.reserve(10); // 优化,预分配10个bytefor (const char& ch : data){if (ch == ','){valsStr.push_back(valStr); // 将每个节点的值存入数组valStr.clear(); // 初始化}else{valStr.push_back(ch); // 存储每个节点的值}}}// Decodes your encoded data to tree.TreeNode* deserialize(string data) {if (data.compare("#") == 0) // 如果整个字符串为空,则直接返回nullptrreturn nullptr;vector<string> valsStr; // 数组字符串存储每个节点信息toStrArr(data, valsStr); // 将string转为数组字符串int size = valsStr.size();TreeNode* root = new TreeNode(std::stod(valsStr[0]));TreeNode* parent = nullptr;std::queue<TreeNode*> nodeQueue;nodeQueue.push(root); // 将根节点压入栈for (int i = 1; i < size; ++i){parent = nodeQueue.front();nodeQueue.pop();if (valsStr[i].compare("#")){parent->left = new TreeNode(std::stod(valsStr[i])); // 创建该节点左子节点nodeQueue.push(parent->left); // 非空则压入栈,顺序访问每个节点}if (valsStr[++i].compare("#")){parent->right = new TreeNode(std::stod(valsStr[i])); // 创建该节点右子节点nodeQueue.push(parent->right); // 非空则压入栈,顺序访问每个节点}}return root; // 返回原始二叉树}
};// Your Codec object will be instantiated and called as such:
// Codec ser, deser;
// TreeNode* ans = deser.deserialize(ser.serialize(root));

结果:

1.4总结

该题是Leecode的一道困难题目,起始如果知道解题思路,则不会很难,要是不知道解题思路,则感觉一头雾水,其解题的核心要点有两个,如果序列化存储二叉树信息到string,然后如何还原该二叉树。要是熟悉二叉树层次遍历的话,可以很快知道之前的层次遍历之所以无法唯一还原一个二叉树是因为没有存储空节点,假如将空节点一起存储,则可以通过二叉树层次遍历每个节点还原出原始二叉树。主要还原要点在输出字符串数组中,第一个是根节点,后面所有紧挨着的两两都是前面序列化时依次压栈的父节点的左右子节点,如果为空而不处理。知道了这点,就可以很容易还原对应的二叉树。

二叉树的序列化和反序列化——C++相关推荐

  1. [Java]LeetCode297. 二叉树的序列化与反序列化 | Serialize and Deserialize Binary Tree

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  2. python代码实现二叉树的序列化和反序列化

    python代码实现二叉树的序列化和反序列化 二叉树的序列化 二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字 符串,从而使得内存中建立起来的二叉树可以持久保存. 二叉树的反序 ...

  3. 二叉树的序列化与反序列化

    题目: 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据. 请设计一个算法来 ...

  4. 算法练习day10——190328(二叉树的先序、 中序、 后序遍历, 包括递归方式和非递归方式、找到一个节点的后继节点、二叉树的序列化和反序列化)

    1.实现二叉树的先序. 中序. 后序遍历, 包括递归方式和非递归方式 1.1 访问节点的顺序 节点访问顺序如下图所示: 访问顺序:1 2 4 4 4 2 5 5 5 2 1 3 6 6 6 3 7 7 ...

  5. 【数据结构与算法】之深入解析“二叉树的序列化与反序列化”的求解思路与算法示例

    一.题目要求 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据. 请设计一个 ...

  6. 数据结构与算法之二叉树的序列化和反序列化及判断一棵树是否为平衡二叉树

    数据结构与算法之二叉树的序列化和反序列化及判断一棵树是否为平衡而二叉树 目录 二叉树的序列化和反序列化 判断一棵树是否为平衡而二叉树 1. 二叉树的序列化和反序列化 1. 递归版本序列化和反序列化 代 ...

  7. 【LeetCode】【HOT】297. 二叉树的序列化与反序列化(BFS)

    [LeetCode][HOT]297. 二叉树的序列化与反序列化 文章目录 [LeetCode][HOT]297. 二叉树的序列化与反序列化 package hot;import java.util. ...

  8. lintcode 7. 二叉树的序列化和反序列化 Python代码

    '''7. 二叉树的序列化和反序列化 描述 设计一个算法,并编写代码来序列化和反序列化二叉树.将树写入一个文件被称为"序列化",读取文件后重建同样的二叉树被称为"反序列化 ...

  9. leetcode-017-297. 二叉树的序列化与反序列化

    我又又又开始刷题了... 不过这么一天两个小时,其实还是蛮浪费时间的,毕竟我对C++其实并不是特别熟悉,所以很多时候花费在语法上面的时间,就很磨人. 序列化是将一个数据结构或者对象转换为连续的比特位的 ...

  10. 一天一大 leet(二叉树的序列化与反序列化)难度:困难 DAY-16

    20200616 题目(难度:困难): 序列化是将一个数据结构或者对象转换为连续的比特位的操作, 进而可以将转换后的数据存储在一个文件或者内存中, 同时也可以通过网络传输到另一个计算机环境,采取相反方 ...

最新文章

  1. 2014百度之星资格赛 1001:Energy Conversion(水题,逻辑题)
  2. Ruby Shanghai 2014年终聚会总结
  3. django mysql api_Django的API操作mysql中常用的语句
  4. java appender_log4j的Appenders配置方法
  5. MySQL数据库的一些基本语法
  6. android 学习资料整理
  7. 从一个程序看继承的有关细节及规则(学习马士兵视频的总结)
  8. 【机器学习】判别模型vs生成模型、概率模型vs非概率模型
  9. 服务器信号满格网速很慢,网速变得很慢(wifi信号满格但网速慢)
  10. pdfpcell输出换行_fpdf 的cell 中文自动换行问题
  11. Python爬虫+颜值打分,5000+图片找到你的Mrs. Right
  12. DVE C++ 中批量注释快捷键 Ctrl + /
  13. python制作相册
  14. C++ sort() 排序函数
  15. Html5大文件断点续传实现方法
  16. pygame像素地图的实现
  17. 计算机专业怎么发顶刊,计算机顶会和顶刊哪个厉害_计算机顶会_顶会
  18. 多多参谋:拼多多改价格降权多久恢复?降权怎么办?
  19. SqlMDF数据提取工具
  20. 论文分享 | 罗强等:GIS领域知识图谱进展研究

热门文章

  1. 短地址TinyURL的API使用
  2. 「景深」和「虚化」有什么区别?如何一键生成背景模糊图片?
  3. 基于计算听觉场景分析的语音增强系统设计
  4. php 如何清除phpsessid,如何在客户端计算机上删除PHPSESSID
  5. css去掉div中图片多余空白高度
  6. el-date-picker 的一些小坑(chang事件不生效以及页面数据不更新)
  7. 【报错】This user agent has been blocked due to abuse 爬虫被封IP解决
  8. linux(虚拟机、Ubuntu):LCD模拟器显示各种颜色
  9. 常见三种求素数的方法
  10. 1052 Linked List Sorting (25 分)