再谈二叉树的序列化与反序列化
最近无聊写写题,又看到这个序列化的题,牛客网序列化二叉树
之前有过两种方式实现1 2,序列化的过程好理解,反序列化则是分别利用先序+中序遍历序列递归重建二叉树或者根据每个节点位置和值迭代方式重建二叉树。这两种序列化的实现都需要额外的空间,序列化后的序列都至少需要两倍的原始节点值空间。
那是否可以有更优雅、更节省空间的序列化方式呢?答案是肯定的。
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过某种符号表示空节点(#),以
!
表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
只有先序遍历序列能够重新构造二叉树吗?可以!
此题已经提示了用某种符号表示空节点,这样包含中止叶子节点(空节点)的二叉树遍历序列其实是可以直接用来重建二叉树的。
- C++版本输出字符序列,一个非常巧妙的方式是直接将int[]数组强制转换为 char[]。
两个辅助函数都使用了C++支持的引用传递,而不是像后面Python版本的全局变量/多参数返回。
这样用-1(0xFFFFFFFF)表示空节点可能会与实际值冲突,最好的解决办法还是以字符存储每位数字,用非数字表示空节点,但数字之间需要额外的分隔符。具体实现可见后面Python的实现方式。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
char* Serialize(TreeNode *root) {
vector<int> vals;
this->PreOrder(root, vals);
int size = vals.size();
int *res = new int[size];
for (int i=0;i<size;i++) res[i] = vals[i];
return (char*)res;
}
void PreOrder(TreeNode *root, vector<int>&vals) {
if (root!=NULL) {
vals.push_back(root->val);
this->PreOrder(root->left, vals);
this->PreOrder(root->right, vals);
} else {
vals.push_back(0xFFFFFFFF); // -1
}
}
TreeNode* BuildTree(int *&p) {
if (*p==0xFFFFFFFF) {
++p;
return NULL;
}
TreeNode *T = new TreeNode(*p);
++p;
T->left = this->BuildTree(p);
T->right = this->BuildTree(p);
return T;
}
TreeNode* Deserialize(char *str) {
int *p = (int *)str;
return this->BuildTree(p);
}
};
- Python实现稍微有点复杂:
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def Serialize(self, root):
# write code here
self.ans = ""
self.PreOrder(root)
return self.ans
def PreOrder(self, root):
if root:
self.ans += "%d|" % root.val
self.PreOrder(root.left)
self.PreOrder(root.right)
else:
self.ans += "#|"
def BuildTree(self, s, pos=0):
if s[pos]=='#':
return None, pos+2
val = 0
for i in range(pos, len(s)):
ch = s[i]
if ch!='|':
val = val*10 + int(ch)
else:
pos = i+1
break
T = TreeNode(val)
T.left, pos = self.BuildTree(s, pos)
T.right, pos = self.BuildTree(s, pos)
return T, pos
def Deserialize(self, s):
# write code here
return self.BuildTree(s)[0]