请实现两个函数,分别用来序列化和反序列化二叉树
Tips:选择先序遍历
序列化时 先用string存‘#’和‘数,’其中数需要用to_string()函数将Int转String
用c_str()将string转char
反序列化时 需要用char**对遍历的位置进行修改(当读到#时 只return不调用 必须修改状态)
或者用 char* 加 int &替代
对于char*传入的内容 需要判断'\0'结尾 结束递归左右子树
自写:方法2的反序列化的二维指针的替换 用一个int的引用时刻记录当前遍历的下一个位置 (之前还考虑过设置私有变量 智障了)
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
void Ser_dfs(TreeNode* node,string& str){
if(!node)
str +='#';
else{
string r = to_string(node->val);
str += r;
str += ',';
Ser_dfs(node->left,str);
Ser_dfs(node->right,str);
}
}
char* Serialize(TreeNode *root) {
if(!root)
return nullptr;
string str;
Ser_dfs(root,str);
char* res = new char[str.size()+1];
strcpy(res,str.c_str());
return res;
}
TreeNode* Deserialize(char *str,int& loc){
TreeNode* root = nullptr;
if(*(str+loc) == '#')
{
loc++;
return root; //返回空 且 loc++
}
int temp = 0;
while(*(str+loc)!=','&&*(str+loc)!='\0')
{
temp = temp*10 + *(str+loc)-'0';
loc++;
}
root = new TreeNode(temp);
if(*(str+loc)=='\0')
return root; //拦截递归
else
loc++;
root->left = Deserialize(str,loc);
root->right = Deserialize(str,loc);
return root;
}
TreeNode* Deserialize(char *str) {
if(!str)
return nullptr;
int p =0;
return Deserialize(str,p);
}
};
自写:方法1序列化时 用vector存入二叉树数值,空用一个特殊值标记存入,并转int* 转char*
反序列化时 char* 转int* 用 int* &来完成遍历和地址的自增
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
typedef int* INT; //mark 有;
class Solution {
public:
vector temp;
void Ser_dfs(TreeNode *root){
if(!root)
temp.push_back(0xabcdef);
else{
temp.push_back(root->val);
Ser_dfs(root->left);
Ser_dfs(root->right);
}
}
char* Serialize(TreeNode *root) {
if(!root)
return nullptr;
Ser_dfs(root);
int* res = new int[temp.size()];
for(unsigned int i=0;ileft = Deserialize(++s);
root->right =Deserialize(s);
return root;
}
}
TreeNode* Deserialize(char *str) {
if(!str)
return nullptr;
int* p = (int*)str;
return Deserialize(p);
}
};
自写: 方法1 再来一次
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
vector temp;
void Ser_dfs(TreeNode* root){
if(!root)
temp.push_back(0xabcdef);
else{
temp.push_back(root->val);
Ser_dfs(root->left);
Ser_dfs(root->right);
}
}
char* Serialize(TreeNode *root) {
if(!root)
return nullptr;
Ser_dfs(root);
int * res = new int [temp.size()];
for(unsigned int i =0;ileft,p);
Deser_dfs(res->right,p);
}
}
TreeNode* Deserialize(char *str) {
if(!str)
return nullptr;
TreeNode* res = nullptr;
int * p = (int *)str;
Deser_dfs(res,p);
return res;
}
};
借鉴方法2: 反序列化的二维指针 很有意思
/*
1. 对于序列化:使用前序遍历,递归的将二叉树的值转化为字符,并且在每次二叉树的结点
不为空时,在转化val所得的字符之后添加一个' , '作为分割。对于空节点则以 '#' 代替。
2. 对于反序列化:按照前序顺序,递归的使用字符串中的字符创建一个二叉树(特别注意:
在递归时,递归函数的参数一定要是char ** ,这样才能保证每次递归后指向字符串的指针会
随着递归的进行而移动!!!)
*/
class Solution {
public:
char* Serialize(TreeNode *root) {
if(root == NULL)
return NULL;
string str;
Serialize(root, str);
char *ret = new char[str.length() + 1];
int i;
for(i = 0; i < str.length(); i++){
ret[i] = str[i];
}
ret[i] = '\0';
return ret;
}
void Serialize(TreeNode *root, string& str){
if(root == NULL){
str += '#';
return ;
}
string r = to_string(root->val);
str += r;
str += ',';
Serialize(root->left, str);
Serialize(root->right, str);
}
TreeNode* Deserialize(char *str) {
if(str == NULL)
return NULL;
TreeNode *ret = Deserialize(&str);
return ret;
}
TreeNode* Deserialize(char **str){//由于递归时,会不断的向后读取字符串
if(**str == '#'){ //所以一定要用**str,
++(*str); //以保证得到递归后指针str指向未被读取的字符
return NULL;
}
int num = 0;
while(**str != '\0' && **str != ','){
num = num*10 + ((**str) - '0');
++(*str);
}
TreeNode *root = new TreeNode(num);
if(**str == '\0')
return root;
else
(*str)++;
root->left = Deserialize(str);
root->right = Deserialize(str);
return root;
}
};
借鉴方法1:O(n)
typedef TreeNode node;
typedef TreeNode* pnode;
typedef int* pint;
class Solution {
vector buf;
void dfs(pnode p){
if(!p) buf.push_back(0x23333);
else{
buf.push_back(p -> val);
dfs(p -> left);
dfs(p -> right);
}
}
pnode dfs2(pint& p){
if(*p == 0x23333){
++p;
return NULL;
}
pnode res = new node(*p);
++p;
res -> left = dfs2(p);
res -> right = dfs2(p);
return res;
}
public:
char* Serialize(TreeNode *p) {
buf.clear();
dfs(p);
int *res = new int[buf.size()];
for(unsigned int i = 0; i < buf.size(); ++i) res[i] = buf[i];
return (char*)res; //将int数组转char*字符串
}
TreeNode* Deserialize(char *str) {
int *p = (int*)str;
return dfs2(p);
}
};
借鉴方法3:层次遍历+非递归
class Solution {
public:
char* Serialize(TreeNode *pRoot) {
string s;
if (!pRoot)
return NULL;
deque q;
q.push_back(pRoot);
while (!q.empty()) {
int n = q.size();
for (int i = 0; i < n; ++i) {
if (q.front()) {
q.push_back(q.front()->left);
q.push_back(q.front()->right);
s += to_string(q.front()->val) + ' ';
} else {
s += "# ";
}
q.pop_front();
}
}
char* chr = strdup(s.c_str());
return chr;
}
TreeNode* Deserialize(char *str) {
if (!str)
return nullptr;
int k = 0;
auto ret = nextNode(str, k);
deque q;
q.push_back(ret);
while (!q.empty()) {
int n = q.size();
for (int i = 0; i < n; ++i) {
q.front()->left = nextNode(str, k);
q.front()->right = nextNode(str, k);
if (q.front()->left)
q.push_back(q.front()->left);
if (q.front()->right)
q.push_back(q.front()->right);
q.pop_front();
}
}
return ret;
}
TreeNode* nextNode(char *str,int &i) {
string s;
while (str[i] != '\0'&&str[i] != ' ') {
if (str[i] == '#') {
i += 2;
return nullptr;
}
s += str[i];
i++;
}
if (str[i] == ' ')
i++;
if (!s.empty())
return new TreeNode(stoi(s));
return nullptr;
}
};
背景介绍:
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。
序列化可以基于 先序、中序、后序、按层 的二叉树遍历方式来进行修改。原理都是一样的(即遍历顺序不同而已,对每个结点的处理都是一样的),序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
c++ 11 to_string()函数 将int转string
转载自:https://blog.csdn.net/lzuacm/article/details/52704931
定义于头文件
std::string to_string( int value ); (1) (C ++11起)
std::string to_string( long value ); (2) (C ++11起)
std::string to_string( long long value ); (3) (C ++11起)
std::string to_string( unsigned value ); (4) (C ++11起)
std::string to_string( unsigned long value ); (5) (C ++11起)
std::string to_string( unsigned long long value ); (6) (C ++11起)
std::string to_string( float value ); (7) (C ++11起)
std::string to_string( double value ); (8) (C ++11起)
std::string to_string( long double value ); (9) (C ++11起)
std::to_string
是C++标准(2011年)的最新版本中引入的功能。旧的编译器可能不支持它。
1) 有符号十进制整数转换为字符串内容相同的std::sprintf(buf, “%d”, value)会产生足够大的buf
.
2) 有符号十进制整数转换为字符串内容相同的std::sprintf(buf, “%ld”, value)会产生足够大的buf
.
3) 有符号十进制整数转换为字符串内容相同的std::sprintf(buf, “%lld”, value)会产生足够大的buf
.
4)std::sprintf(buf, "%u", value)
会产生足够大的buf
了同样内容的一个字符串转换成一个无符号十进制整数.
5)std::sprintf(buf, "%lu", value)
会产生足够大的buf
了同样内容的一个字符串转换成一个无符号十进制整数.
6)std::sprintf(buf, "%llu", value)
会产生足够大的buf
了同样内容的一个字符串转换成一个无符号十进制整数.
6)std::sprintf(buf, "%llu", value)
会产生足够大的buf
了同样内容的一个字符串转换成一个无符号十进制整数.
@ 7,8 @std::sprintf(buf, "%f", value)
会产生足够大的buf
了同样内容的一个字符串转换成一个浮点值.
9) std::sprintf(buf, "%Lf", value)
会产生足够大的buf
了同样内容的一个字符串转换成一个浮点值.
value - 一个数值转换
一个字符串保持转换后的值