第二十五题
代码比较长 利用层序遍历 保存序列以及还原序列
注意:字符表示的范围;哪些算是空节点?如何表示和判断空节点?
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
// 用来表示当前结点不是一个结点 但因为需要留出二叉树的位置 而填充的(表示空)
TreeNode* notnode=new TreeNode(-1);
char* Serialize(TreeNode *root) {
// 用层序比较简单
// 先知道深度,之后 根据深度对应深度的满二叉树的序列
// 还原就是将满二叉树序列 恢复成树
// 知道深度 2^深度-1就是满二叉树的结点个数
int depth = getdepth(root);
// cout<<depth<<endl;
// ret_ans用来存储返回的序列
// 长度为 2^深度+1
// 第一个是空 为了数组访问直接从1开始
// 最后一个是自己填充的151 因为数据表示在0-150 之间 不超过151 151就用来记录ret_ans这个序列结束了
char *ret_ans=new char[int(pow(2,depth)+1)];
// 用于层次遍历 保存后续结点的队列
queue<TreeNode *> p;
// 第一次先把根节点放进去
p.push(root);
// 记录当前在第几层从1开始计算
int level=1;
// 层次遍历 如果队列不是空,则继续往下遍历
// 从第一层开始 处理完深度的树
while( level<=depth ){
// length表示这一层存有几个 决定了之后要遍历的次数
int length = p.size();
int k=0;
// 和之字形套路一样 只用队列中的length个
while(length--)
{
// 如果说 这个点是我自己预留出来的空节点 也就是val=-1
if(p.front()->val==-1){
p.pop();
// char # 表示为空 在第二个要求 转换回二叉树的时候要用到
ret_ans[int(pow(2,level-1))+k] = '#';
k++;
// 每一个空节点 会产生连个子空节点
p.push(notnode);
p.push(notnode);
continue;
}
// 访问当前结点
TreeNode* thisnode = p.front();
p.pop();
// 把该节点的数据存到序列中
// 每个点的位置是:2^(当前level) +k
// 这里为什么要-128 是因为 char类型表示的是[-128,128] 但是范围是[0,150] 后面太大的数会导致溢出
// 所以减去128 并在还原的时候加上128
ret_ans[int(pow(2,level-1))+k]=char(thisnode->val-128);
k++;
// 如果左右孩子还有 就push进队列(记住,此时所有入得队列 都代表是下一层的)
// 反之,如果左右孩子是空 就push notnode (用来保证所传递的序列 位置上是有东西的)
if(thisnode->left!=NULL)
p.push(thisnode->left);
else
p.push(notnode);
if(thisnode->right!=NULL)
p.push(thisnode->right);
else
p.push(notnode);
}
// 到下一层处理
level++;
}
// 可以取消注释 看一眼所有保存到序列的值
// for (int i =1;i<int(pow(2,depth));i++){
// cout<<i<<ret_ans[i]<<" ";
// }
// 在最后一个位置插入151 表示 序列结束
int a=151;
ret_ans[int(pow(2,depth))] = char(a);
return ret_ans;
}
// 序列转化为二叉树
TreeNode* Deserialize(char *str) {
// 结果
TreeNode *tree_ans;
// 统计长度 决定了后面创建树的循环的次数
int length=0;
for(int i =0;;i++)
{
// 151 在这里用上了 当数字是151 表示结束了
int a=151;
if(str[i]!=char(a))
length++;
else
break;
}
// 因为str第0个位置空的 所以真正的长度是length-1
// cout<<length-1<<endl;
// 如果说 长度为0 返回空树
if(length-1 == 0)
return NULL;
// 开始构造树 每个树都要创建出一个结点
tree_ans=new TreeNode(0);
// 层次遍历的队列
queue<TreeNode*> q;
TreeNode* temp;
q.push(tree_ans);
// 循环次数 就是看传来的序列有几个字 也代表了 树有几个结点
for (int i =1 ; i<length ; i++)
{
// 获取要处理的结点
temp=q.front();
q.pop();
// 如果说不是# 代表原来是结点 要进行处理
if(str[i]!='#')
{
// 下面两个if else 决定了是否有左右孩子,如果有左右孩子 就创建出一个新的树的结点 并放入队列
// 如果没有左(右)孩子,就push一个空 保证树的位置正确。
// 通过树父亲结点i的两个孩子分别是 2*i 和 2*i+1 来判断
if(i*2<=length-1 && str[i*2]!='#')
{
temp->left=new TreeNode(0);
q.push(temp->left);
}
else
q.push(notnode);
if(i*2+1 <=length-1 && str[i*2+1]!='#')
{
temp->right=new TreeNode(0);
q.push(temp->right);
}
else
q.push(notnode);
// 还原结点 加上128 因为之前减了128
temp->val=str[i]+128;
}
// 如果字符是# 代表原来是个空节点 让存进来的结点依旧保持为空
else
{
temp=NULL;
// 一个空节点 下面就会有两个空孩子 放入队列 保证 创建树的正确性
q.push(notnode);
q.push(notnode);
}
}
return tree_ans;
}
// 知道深度 递归调用 就不说了
int getdepth(TreeNode *root){
int depth=0;
if(root==NULL)
return depth;
int leftdepth=getdepth(root->left);
int rightdepth = getdepth(root->right);
depth = leftdepth > rightdepth ? leftdepth:rightdepth;
return depth+1;
}
};
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
// 用来表示当前结点不是一个结点 但因为需要留出二叉树的位置 而填充的(表示空)
TreeNode* notnode=new TreeNode(-1);
char* Serialize(TreeNode *root) {
// 用层序比较简单
// 先知道深度,之后 根据深度对应深度的满二叉树的序列
// 还原就是将满二叉树序列 恢复成树
// 知道深度 2^深度-1就是满二叉树的结点个数
int depth = getdepth(root);
// cout<<depth<<endl;
// ret_ans用来存储返回的序列
// 长度为 2^深度+1
// 第一个是空 为了数组访问直接从1开始
// 最后一个是自己填充的151 因为数据表示在0-150 之间 不超过151 151就用来记录ret_ans这个序列结束了
char *ret_ans=new char[int(pow(2,depth)+1)];
// 用于层次遍历 保存后续结点的队列
queue<TreeNode *> p;
// 第一次先把根节点放进去
p.push(root);
// 记录当前在第几层从1开始计算
int level=1;
// 层次遍历 如果队列不是空,则继续往下遍历
// 从第一层开始 处理完深度的树
while( level<=depth ){
// length表示这一层存有几个 决定了之后要遍历的次数
int length = p.size();
int k=0;
// 和之字形套路一样 只用队列中的length个
while(length--)
{
// 如果说 这个点是我自己预留出来的空节点 也就是val=-1
if(p.front()->val==-1){
p.pop();
// char # 表示为空 在第二个要求 转换回二叉树的时候要用到
ret_ans[int(pow(2,level-1))+k] = '#';
k++;
// 每一个空节点 会产生连个子空节点
p.push(notnode);
p.push(notnode);
continue;
}
// 访问当前结点
TreeNode* thisnode = p.front();
p.pop();
// 把该节点的数据存到序列中
// 每个点的位置是:2^(当前level) +k
// 这里为什么要-128 是因为 char类型表示的是[-128,128] 但是范围是[0,150] 后面太大的数会导致溢出
// 所以减去128 并在还原的时候加上128
ret_ans[int(pow(2,level-1))+k]=char(thisnode->val-128);
k++;
// 如果左右孩子还有 就push进队列(记住,此时所有入得队列 都代表是下一层的)
// 反之,如果左右孩子是空 就push notnode (用来保证所传递的序列 位置上是有东西的)
if(thisnode->left!=NULL)
p.push(thisnode->left);
else
p.push(notnode);
if(thisnode->right!=NULL)
p.push(thisnode->right);
else
p.push(notnode);
}
// 到下一层处理
level++;
}
// 可以取消注释 看一眼所有保存到序列的值
// for (int i =1;i<int(pow(2,depth));i++){
// cout<<i<<ret_ans[i]<<" ";
// }
// 在最后一个位置插入151 表示 序列结束
int a=151;
ret_ans[int(pow(2,depth))] = char(a);
return ret_ans;
}
// 序列转化为二叉树
TreeNode* Deserialize(char *str) {
// 结果
TreeNode *tree_ans;
// 统计长度 决定了后面创建树的循环的次数
int length=0;
for(int i =0;;i++)
{
// 151 在这里用上了 当数字是151 表示结束了
int a=151;
if(str[i]!=char(a))
length++;
else
break;
}
// 因为str第0个位置空的 所以真正的长度是length-1
// cout<<length-1<<endl;
// 如果说 长度为0 返回空树
if(length-1 == 0)
return NULL;
// 开始构造树 每个树都要创建出一个结点
tree_ans=new TreeNode(0);
// 层次遍历的队列
queue<TreeNode*> q;
TreeNode* temp;
q.push(tree_ans);
// 循环次数 就是看传来的序列有几个字 也代表了 树有几个结点
for (int i =1 ; i<length ; i++)
{
// 获取要处理的结点
temp=q.front();
q.pop();
// 如果说不是# 代表原来是结点 要进行处理
if(str[i]!='#')
{
// 下面两个if else 决定了是否有左右孩子,如果有左右孩子 就创建出一个新的树的结点 并放入队列
// 如果没有左(右)孩子,就push一个空 保证树的位置正确。
// 通过树父亲结点i的两个孩子分别是 2*i 和 2*i+1 来判断
if(i*2<=length-1 && str[i*2]!='#')
{
temp->left=new TreeNode(0);
q.push(temp->left);
}
else
q.push(notnode);
if(i*2+1 <=length-1 && str[i*2+1]!='#')
{
temp->right=new TreeNode(0);
q.push(temp->right);
}
else
q.push(notnode);
// 还原结点 加上128 因为之前减了128
temp->val=str[i]+128;
}
// 如果字符是# 代表原来是个空节点 让存进来的结点依旧保持为空
else
{
temp=NULL;
// 一个空节点 下面就会有两个空孩子 放入队列 保证 创建树的正确性
q.push(notnode);
q.push(notnode);
}
}
return tree_ans;
}
// 知道深度 递归调用 就不说了
int getdepth(TreeNode *root){
int depth=0;
if(root==NULL)
return depth;
int leftdepth=getdepth(root->left);
int rightdepth = getdepth(root->right);
depth = leftdepth > rightdepth ? leftdepth:rightdepth;
return depth+1;
}
};