C++ 二叉树序列化与反序列化

本人微信公众号:CPP进阶之旅
如果觉得这篇文章对您有帮助,欢迎关注 “CPP进阶之旅” 学习更多技术干货

1、题目要求

  请实现两个函数,分别用来序列化和反序列化二叉树?

2、题目说明

  序列化的意思是指将一些特定的数据结构,变成有格式信息的字符串。例如对一个链表,可以将1->2->3->4->NULL序列化为"1,2,3,4"。对于序列化算法,必须支持反序列化,即在约定的格式下,可以将满足格式要求的字符串重新构造为原始的结构形式。
  二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串。
  二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果string,重构出原始的二叉树结构。

3、核心问题

  拿到这个题目,我们面临着两个至关重要的问题:
  1、题目是要求序列化二叉树,对于二叉树这种数据结构,很可能存在着空节点,那么,对于空节点,该怎么表示呢?
  2、题目要求实现二叉树的反序列化,我们按照将二叉树序列化为一个字符串的前提,对于一个字符串,我们怎么区分出每个独立的二叉树的节点呢?
以上两个问题,在很多刷题网站会直接给出结论或者结果,这样降低了题目的难度,但作为面试者需要清楚,即使没有提示我们也要注意到这两点问题。即空节点用特殊字符"#"表示,每个节点用逗号“,”分割。也就是反序列化的时候遇到#那么就表示该节点为空节点,可以结束该字符的遍历了。而拆分节点的时候我们只需要取出两个逗号之间的数据即是该节点的值。

4、解题思路

  1.序列化二叉树,借助string类型来拼接序列化的字符串。只需要前序遍历二叉树,当遇到根节点为空时,追加"#",并退出递归,否则追加二叉树的根节点值,接着追加逗号。接下来只需递归实现左子树和右子树的序列化。那么,序列化之后就得到了string类型的字符串。
  2.反序列化二叉树,如果string为空,则直接返回退出。如果遇到"#",则为空节点,退出递归。否则,找到字符数组中的一个二叉树节点值,然后构造根节点,如果此时到达字符末尾,直接返回根节点,否则继续遍历。接下来根结点的左右指针分别连接左子树的递归实现结果和右子树的递归实现结果。

5、代码实现

//二叉树结构
struct TreeNode {
    int val;
    struct TreeNode* left;
    struct TreeNode* right;
    TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}
};
//序列化二叉树
//to_string将每个结点的val值转化为string类型存储在str上。
void Serialize(TreeNode* node, string& s)
{
    if (node == nullptr)
    {
        s.push_back('#');
        s.push_back(',');
        return;
    }
    s += to_string(node->val);
    s.push_back(',');
    Serialize(node->left, s);
    Serialize(node->right, s);
}

//反序列化二叉树
TreeNode* Deserialize(string& s)
{
    if (s.empty())
        return nullptr;
    if (s[0] == '#')
    {
        s = s.substr(2);
        return nullptr;
    }
    TreeNode* node = new TreeNode(stoi(s));
    s = s.substr(s.find_first_of(',') + 1);
    node->left = Deserialize(s);
    node->right = Deserialize(s);
    return node;
}

6、问题扩展

  问题1. 将题目中的节点值类型由int换为string,我们还能用"#“来表示空节点吗?还能用”,“来分割节点吗?
  问题2. Serialize里使用了”+=",他的复杂度是怎样的,请分析一下?
  提示一下,问题1,解决的思路类似于网络请求中请求参数的处理。问题2,主要是考察了string的操作符重载的过程。

7、重要说明

欢迎关注我的个人微信公众号,查看专业的客户端/服务端开发知识、笔试面试题目、程序员职场经验与心得分享。
在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
叉树序列序列是将一棵二叉树的状态转换为一个字符串,然后又恢复成原来的二叉树的过程,通常用于数据存储和在网络中传输。在C++中,我们可以使用自定义的数据结构和迭代方法来实现这个功能。 **序列(Serialization)**: 1. 定义一个序列的格式,常见的如前序遍历(根-左-右)或中序遍历(左-根-右)的字符串表示。 2. 创建一个函数,接受二叉树的根节点作为输入,使用递归的方式访问每个节点,并将其值和子节点信息添加到序列中。如果节点为空,可以用特殊标记(如“#”或“null”)表示。 3. 返回最终序列的字符串。 ```cpp string serialize(TreeNode* root) { // 假设使用前序遍历 stack<TreeNode*> nodes; nodes.push(root); string result = ""; while (!nodes.empty()) { TreeNode* node = nodes.top(); nodes.pop(); if (node) { result += to_string(node->val) + ','; nodes.push(node->left); nodes.push(node->right); } else { result += "#,"; } } return result.substr(0, result.length() - 1); // 去掉末尾逗号 } ``` **序列(Deserialization)**: 1. 创建一个函数,接受一个字符串作为输入,恢复成二叉树。首先,从字符串中分割出节点值和子节点信息。 2. 用堆栈或队列模拟前序或中序遍历的过程,根据节点值创建新的节点,并将它们连接起来。 3. 当遇到“#”或“null”时,表示当前节点为空,停止添加子节点。 ```cpp TreeNode* deserialize(string data) { if (data == "") return nullptr; stack<TreeNode*> nodes; char* token = strtok(data.c_str(), ","); while (token != nullptr) { int val = stoi(token); if (isdigit(val)) { // 创建新节点并入栈 TreeNode* node = new TreeNode(val); nodes.push(node); if (nodes.top()->left == nullptr) { nodes.top()->left = nodes.top()->right = nullptr; // 初始为 null } else { TreeNode* parent = nodes.top(); if (parent->left == nullptr) { parent->left = node; } else { parent->right = node; } } } else { nodes.top()->left = deserialize(next_token); nodes.top()->right = deserialize(next_token); token = strtok(nullptr, ","); } } return nodes.top(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值