题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
解题思路
这里选用层次遍历的方式序列化二叉树。并非递归的实现反序列化。
- 二叉树的序列化过程比较简单,相比层次遍历的过程,只用将一般遍历过程中元素访问操作改为数值的字符化,并用“!”分隔不同元素,遇到空结点用“#!”代替。
- 反序列化过程就比较繁琐,很多细节需要注意,例如对于给定的需要反序列化的字符串str("1!2!33!#!4!#!#!#!#!"),除了‘#’外,每一个分隔符‘!’前面的数字都是二叉树中的一个有效结点,因为每个数字的位数不定,需要注意字符串遍历指针的步长,不能简单进行+2处理。
对于层次遍历得来的序列化字符串,其反序列化(二叉树重构)过程如下:
1)若str="#!"或"\0",代表原二叉树为空,直接返回NULL;
2)初始化两个辅助队列p、q,字符串遍历指针ptr,从根结点开始重构树结点,注意保持字符串遍历指针始终指向当前树结点的孩子在字符串中的位置。以字符串str("1!2!33!#!4!#!#!#!#!")为例,重构根结点root时,ptr指向root的左孩子所在位置(字符串中2所在的位置)。
3)两个队列存放的都是已经完成val初始化但是没有完成左右孩子结点初始化工作的树结点。
4)根节点root入队列p;
5)只要队列p或q不为空,循环访问当前不为空的队列,不断从队头取出树结点,完成当前取出结点curNode的左右孩子初始化,如果ptr当前指向字符为‘#’,代表curNode的左孩子为空,ptr前进两个位置,指向curNode的右孩子;如果ptr当前指向字符不为‘#’,即curNode有左孩子,为左孩子申请空间并初始化其val为(*ptr),同时将新初始化的左孩子结点放入另一个队列q中,同时注意此时ptr前移的步长;右孩子的初始化工作也是一样的;
6)当前队列为空转入另一个队列的循环访问程序,直到两个队列都为空。
有点复杂,好像讲的不是很明白,还是直接看代码吧:(
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
private:
string str;
public:
char* Serialize(TreeNode *root) {
LevelTraverse(root,str);
char *pstr=const_cast<char*>(str.c_str());
return pstr;
}
TreeNode* Deserialize(char *str) {
if(*str=='#' || *str=='\0') return NULL;
queue<TreeNode*> p,q;
char *p1=str;
TreeNode* root=(TreeNode*)malloc(sizeof(TreeNode));
root->val=getint(&p1);
p.push(root);
TreeNode* curNode;
while(!p.empty() || !q.empty()){
while(!p.empty()){
curNode=p.front();
p.pop();
if(*p1 != '#'){
TreeNode* l=(TreeNode*)malloc(sizeof(TreeNode));
l->val=getint(&p1);
curNode->left=l;
q.push(l);
}
else{
curNode->left=NULL;
p1+=2;
}
if(*p1 != '#'){
TreeNode* r=(TreeNode*)malloc(sizeof(TreeNode));
r->val=getint(&p1);
curNode->right=r;
q.push(r);
}
else{
curNode->right=NULL;
p1+=2;
}
}
while(!q.empty()){
curNode=q.front();
q.pop();
if(*p1 != '#'){
TreeNode* l=(TreeNode*)malloc(sizeof(TreeNode));
l->val=getint(&p1);
curNode->left=l;
p.push(l);
}
else{
curNode->left=NULL;
p1+=2;
}
if(*p1 != '#'){
TreeNode* r=(TreeNode*)malloc(sizeof(TreeNode));
r->val=getint(&p1);
curNode->right=r;
p.push(r);
}
else{
curNode->right=NULL;
p1+=2;
}
}
}
return root;
}
void LevelTraverse(TreeNode *root,string &str){
if(!root) str="#!";
queue<TreeNode*> q;
q.push(root);
TreeNode *curNode;
while(!q.empty()){
curNode=q.front();
q.pop();
if(curNode){
str+=to_string(curNode->val)+'!';
q.push(curNode->left);
q.push(curNode->right);
}
else{
str+="#!";
}
}
}
int getint(char **p){
int val=0;
while((**p)!='!'){
val=10*val+((**p)-'0');
++(*p);
}
++(*p);
return val;
}
};
上述代码中还有一些细节需要注意:
- 层次遍历的结果为什么先保存在string中,然后转换为
char*
,遍历的时候不能直接使用char*
吗? - C++中string与
char*
的转换问题; - C++中字符数字与整型数字的相互转换。
emmmmmmmm,自己总结完,发现其实一个辅助队列就行了,傻了...
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
private:
string str;
public:
char* Serialize(TreeNode *root) {
LevelTraverse(root,str);
char *pstr=const_cast<char*>(str.c_str());
return pstr;
}
TreeNode* Deserialize(char *str) {
if(*str=='#' || *str=='\0') return NULL;
queue<TreeNode*> q;
char *p1=str;
TreeNode* root=(TreeNode*)malloc(sizeof(TreeNode));
root->val=getint(&p1);
q.push(root);
TreeNode* curNode;
while(!q.empty()){
curNode=q.front();
q.pop();
if(*p1 != '#'){
TreeNode* l=(TreeNode*)malloc(sizeof(TreeNode));
l->val=getint(&p1);
curNode->left=l;
q.push(l);
}
else{
curNode->left=NULL;
p1+=2;
}
if(*p1 != '#'){
TreeNode* r=(TreeNode*)malloc(sizeof(TreeNode));
r->val=getint(&p1);
curNode->right=r;
q.push(r);
}
else{
curNode->right=NULL;
p1+=2;
}
}
return root;
}
void LevelTraverse(TreeNode *root,string &str){
if(!root) str="#!";
queue<TreeNode*> q;
q.push(root);
TreeNode *curNode;
while(!q.empty()){
curNode=q.front();
q.pop();
if(curNode){
str+=to_string(curNode->val)+'!';
q.push(curNode->left);
q.push(curNode->right);
}
else{
str+="#!";
}
}
}
int getint(char **p){
int val=0;
while((**p)!='!'){
val=10*val+((**p)-'0');
++(*p);
}
++(*p);
return val;
}
};
网友评论