【序列化与反序列化】【二叉搜索树】【二叉树】
449. 序列化和反序列化二叉搜索树
设计类的题目,实现二叉搜索树的两个功能:
对序列化和反序列的工作方式没有限制,保存二叉搜索树通常有前序、中序、后续以及层序遍历保存的形式,因此,序列化/反序列可以使用以上四种遍历保存方式的任意一种。
我们使用前序遍历的方式来进行序列化和反序列化。前序遍历的方式是先遍历根节点,再递归遍历左子节点,再递归遍历右子节点,对于每个递归也是按照先遍历根节点,再遍历左子节点,最后再遍历右子节点的顺序进行。
对于序列化,我们进行这样的设计:
str
字符串中;'!'
将各个节点值分隔开;'#'
表示;最后,输出前序遍历后得到的字符串 str
即为序列化结果。这里的前序遍历是使用递归来实现的,其他几种方式的实现可以参考 二叉树的遍历方式与实现。
反序列化需要根据序列化的方式来进行,序列化使用的是前序遍历的方式,那么发序列化就要按照前序遍历的方式进行,具体地:
str
中首元素是根节点值,根据值建立根节点;具体实现中,我们可以需要先把字符串 str
按照从左到右的顺序加入到队列 que
中,利用队列特性方便弹出根节点,利用剩下的节点建立子树。
实现代码
/**
* 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:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
if(root == nullptr) {
return "#!";
}
string res;
res = to_string(root->val) + "!";
res += serialize(root->left);
res += serialize(root->right);
return res;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(queue<string>& que) {
string values = que.front();
que.pop();
if(values == "#") {
return nullptr;
}
TreeNode *root = new TreeNode(stoi(values));
root->left = deserialize(que);
root->right = deserialize(que);
return root;
}
TreeNode* deserialize(string data) {
// 以 ! 为分隔符存入队列
queue<string> que;
string str;
for(int i = 0; i < data.size(); ++i) {
if(data[i] == '!') {
que.push(str);
str = "";
}
else {
str += data[i];
}
}
return deserialize(que);
}
};
// Your Codec object will be instantiated and called as such:
// Codec* ser = new Codec();
// Codec* deser = new Codec();
// string tree = ser->serialize(root);
// TreeNode* ans = deser->deserialize(tree);
// return ans;
时间复杂度: O ( n ) O(n) O(n), n n n 为二叉搜索树的节点数量,序列化和反序列的最坏时间复杂度都是 O ( n ) O(n) O(n);
空间复杂度: O ( 2 n − n ) O(2^n-n) O(2n−n),最坏情况了树的高度为 n
,树的每一层只有一个节点,其余都是空节点,一共要使用 2 n − n − 1 2^n-n-1 2n−n−1 个额外空间,队列使用的空间也是。
关于以上的复杂度分析不知道有没有问题,欢迎大家一起讨论。
以上就是本篇文章的内容了,感谢您的阅读。
如果感到有所收获的话可以给博主点一个 哦。
如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出。