剑指37:序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树

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 - 一个数值转换

返回值

一个字符串保持转换后的值

你可能感兴趣的:(剑指offer2,c++)