0
点赞
收藏
分享

微信扫一扫

[二叉树]BM39 序列化二叉树-较难

描述

请实现两个函数,分别用来序列化和反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。

二叉树的序列化(Serialize)是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树等遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#)


二叉树的反序列化(Deserialize)是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

例如,可以根据层序遍历的方案序列化,如下图:[二叉树]BM39 序列化二叉树-较难_反序列化层序序列化(即用函数Serialize转化)如上的二叉树转为"{1,2,3,#,#,6,7}",再能够调用反序列化(Deserialize)将"{1,2,3,#,#,6,7}"构造成如上的二叉树。

当然你也可以根据满二叉树结点位置的标号规律来序列化,还可以根据先序遍历和中序遍历的结果来序列化。不对序列化之后的字符串进行约束,所以欢迎各种奇思妙想。

数据范围:节点数 [二叉树]BM39 序列化二叉树-较难_字符串_02,树上每个节点的值满足 [二叉树]BM39 序列化二叉树-较难_序列化_03要求:序列化和反序列化都是空间复杂度 [二叉树]BM39 序列化二叉树-较难_反序列化_04,时间复杂度 [二叉树]BM39 序列化二叉树-较难_反序列化_04

示例1

输入:

{1,2,3,#,#,6,7}

复制返回值:

{1,2,3,#,#,6,7}

复制说明:

如题面图

示例2

输入:

{8,6,10,5,7,9,11}

复制返回值:

{8,6,10,5,7,9,11}


题解

方法一:使用层次遍历存放完全二叉树

思想:

使用一个数组存放输入二叉树的层次遍历,并且将该二叉树补全成一颗完全二叉树直到叶结点的子节点那一层。代码如下:

// https://www.nowcoder.com/practice/cf7e25aa97c04cc1a68c8f040e71fb84?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj

#include <bits/stdc++.h>

struct TreeNode
{
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

char *Serialize(TreeNode *root)
{
if (root == nullptr)
{
return nullptr;
}

std::vector<std::vector<TreeNode *>> v;// 存放层次遍历的结果
std::queue<TreeNode *> q;// 层次遍历辅助队列
q.push(root);
while (!q.empty())
{
int n = q.size();
std::vector<TreeNode *> level;
int null_count = 0;// 记录当前这层的空节点个数,如果所有的节点都为空,则结束遍历
int i = 0;
while (i < n)
{
auto node = q.front();
q.pop();
level.push_back(node);
if (node != nullptr)
{
q.push(node->left);
q.push(node->right);
}
else// 如果当前节点为空,将其左右节点也补为空节点,为的是让数组在形式上表现为一个完全二叉树
{
q.push(nullptr);
q.push(nullptr);
null_count++;
}
}
if (null_count >= n)
{
break;
}
v.push_back(level);
}

std::string data;
for (int i = 0; i < v.size(); ++i)
{
for (int k = 0; k < v[i].size(); ++k)
{
auto node = v[i][k];
if (node == nullptr)
{
data.append(1, '#');
}
else
{
data += std::to_string(node->val);
}
data.append(1, ',');
}
}
char *str = new char[data.size() + 1];
strncpy(str, data.data(), data.size());
str[data.size()] = '\0';
return str;
}

TreeNode *Deserialize(char *str)
{
if (str == nullptr)
{
return nullptr;
}
TreeNode *root = nullptr;
int i = 0;
std::vector<TreeNode *> v;
while (str[i] != '\0')// 从字符串恢复成数组
{
TreeNode *node = nullptr;
if (str[i] == '#')
{
v.push_back(nullptr);
i += 2;
}
else
{
int n = 0;
while (str[i] != ',')
{
n = n * 10 + (str[i] - '0');
i++;
}
v.push_back(new TreeNode(n));
i++;
}
}

for (int i = 0; i < v.size() / 2; ++i)// 由于是完全二叉树,因此只需要根据下标将当前节点和它的左右节点连接起来即可
{
if (v[i] != nullptr)
{
v[i]->left = v[i * 2 + 1];
v[i]->right = v[i * 2 + 2];
}
}
return v[0];
}


其他解法

参考牛客网的实现。

  • 使用先序遍历的实现
  • 使用层次遍历的实现
举报

相关推荐

0 条评论