题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
思路
这道题简直恶心至极让人绝望,大概因为我是个菜逼。。
序列化:按照层次遍历得到的,不用多说
逆序列化思路:
假设 字符串是 1!2!3!4!5!#!6!#!#!#!#!#!7!#!#!
对应的结构是:
1
2 3
4 5 NULL 6
NULL NULL NULL NULL NULL 7
我们的序列化算法中默认NULL是没有子树的,因此第三层的NULL没有子树,第四层只有4,5,6的子树。
首先将字符串转换为一个结点队列
其次是重组二叉树
过程如下:
First :
q_Tree_2 1
q_Tree_1 2 3 4 5 NULL 6 NULL NULL NULL NULL NULL 7
这一步将1pop出来,把2和3挨个pop出来,并安排为1的左右子树,并将2和3压到q_Tree_2 中
Second:
q_Tree_2 2 3
q_Tree_1 4 5 NULL 6 NULL NULL NULL NULL NULL 7
依次将2和3pop出来,将4,5NULL,6pop出来,但是需要注意的是,3的左子树是NULL,不需要给他分配子结点,则不需将NULL压入q_Tree_2
Third:
q_Tree_2 4 5 6
q_Tree_1 NULL NULL NULL NULL NULL 7
Four:
q_Tree_2 7
q_Tree_1
Finish!
代码
class Solution {
public:
queue<TreeNode*> q_Tree_1;
queue<TreeNode*> q_Tree_2;
/* 我这里用了层次遍历,这个就不赘述了,大家应该都知道*/
char* Serialize(TreeNode *root) {
char* res;
string serial;
if (root == NULL)
{
res = new char[3]();
res[0] = '#';
res[1] = '!';
return res;
}
queue<TreeNode*> q_Tree;
q_Tree.push(root);
while (q_Tree.size() > 0)
{
TreeNode* current = q_Tree.front();
q_Tree.pop();
if (current == NULL)
{
serial = serial + '#' + '!';
}
else
{
serial = serial + to_string(current->val) + '!';
if (current->left == NULL && current->right == NULL)
{
continue;
}
else
{
q_Tree.push(current->left);
q_Tree.push(current->right);
}
}
}
int a = serial.size();
char* res_2= new char[a + 1]();
memcpy(res_2, serial.c_str(), a);
return res_2;
}
/* 这个是逆序列函数,将一段字符串换成一堆结点保存到q_Tree_1中 */
TreeNode* Deserialize(char *str) {
string s = str;
if (s.size() == 0 || s[0] == '#')
{
return NULL;
}
int end = 0;
while (end < s.size())
{
TreeNode* node = sring_node(s, end, s.find("!", end + 1));
q_Tree_1.push(node);
if (end == s.size())
break;
else
end = s.find("!", end + 1) + 1;
}
TreeNode* root;
root = Deserialize_sub();
return root;
}
/* 这个函数是将一段字符转换为数字,start标志上一个!的下一位,end表示这次找到的!,二者就将这个结点数字对应的字符取出*/
TreeNode* sring_node(string s,int start, int end)
{
int number = 0;
for (int i = start; i < end; i++)
{
if (s[i] == '#')
{
return NULL;
}
else
{
number = number + (s[i] - '0')*pow(10, end - i - 1);
}
}
TreeNode* node = new TreeNode(number);
return node;
}
/* 这个函数是将结点重构成树,利用两个队列,队列1保存剩余结点,队列2保存下次分配子结点的那些结点。特别需要注意的!调了2个小时才明白的!每次队列1pop之后,需要判断pop出来的是不是NULL,NULL的就不push到队列2中,因为NULL没有子树*/
TreeNode* Deserialize_sub()
{
if (q_Tree_1.size() == 0)
return NULL;
int count = 0;
TreeNode* root;
root = q_Tree_1.front();
q_Tree_1.pop();
q_Tree_2.push(root);
while (q_Tree_1.size()>0)
{
int size = q_Tree_2.size();
for (int i = 0; i < size; i++)
{
TreeNode* node = q_Tree_2.front();
q_Tree_2.pop();
TreeNode* node_left = q_Tree_1.front();
q_Tree_1.pop();
node->left = node_left;
TreeNode* node_right = q_Tree_1.front();
q_Tree_1.pop();
node->right = node_right;
if(node_left) q_Tree_2.push(node_left);
if(node_right) q_Tree_2.push(node_right);
}
count++;
}
return root;
}
};