lintcode Serialize and Deserialize Binary Tree

一、题意

二叉树的序列化和反序列化。
样例

给出一个测试数据样例, 二叉树{3,9,20,#,#,15,7},表示如下的树结构:
这里写图片描述

二、题解

主要还是理解完全二叉树的构造,对于节点i,它的左右儿子节点的id分别是2*i+1和2*i+2. 其他都没什么难的,主要是记录code的过程中遇到的坑。

三、代码

#include <iostream>
#include<vector>
using namespace std;

class TreeNode {
public:
  int val;
  TreeNode *left, *right;
  TreeNode(int val) {
      this->val = val;
      this->left = this->right = NULL;
  }
};



class Solution {
public:
    /**
     * This method will be invoked first, you should design your own algorithm
     * to serialize a binary tree which denote by a root node to a string which
     * can be easily deserialized by your own "deserialize" method later.
     */
    //最大的节点的编号
    int maxNode ;

    //处理root当前节点的序列化
    void serializeFunc(TreeNode * root,int val[],int Idx){
        if(root==NULL)
            return;
        //计算最大的节点的编号
        if(Idx>maxNode)
            maxNode = Idx;

        val[Idx] = root->val;

        int l = Idx*2+1;
        int r = Idx*2+2;
        if(root->left)
            serializeFunc(root->left, val, l);
        if(root->right)
            serializeFunc(root->right, val, r);
    }

    string serialize(TreeNode * root) {
        // write your code here
        int val[10005]={0};

        maxNode = -1;
        serializeFunc(root, val, 0);
        char s[10005]= {};
        int s_len = 0;
        for(int i=0; i<=maxNode; i++) {
            int len;
            if (!val[i])
                len = snprintf(s+s_len, 100, "%s,", "#");
            else
                len = snprintf(s+s_len, 100, "%d,", val[i]);
            s_len += len;
        }
        s[s_len-1] = '\0';
        string res = s;
        return res;
    }

    /**
     * This method will be invoked second, the argument data is what exactly
     * you serialized at method "serialize", that means the data is not given by
     * system, it's given by your own serialize method. So the format of data is
     * designed by yourself, and deserialize it here as you serialize it in
     * "serialize" method.
     */
    //建立root节点的儿子节点
    void ConductTree(TreeNode *root,vector<string> &dArray,int idx,int len){

        int l = 2*idx+1;
        int r = 2*idx+2;
        if(l<len && dArray[l].compare("#")){
            TreeNode *lPoint = new TreeNode(stoi(dArray[l]));
            root->left = lPoint;
            ConductTree(lPoint, dArray, l, len);
        }
        if(r<len && dArray[r].compare("#")){
            TreeNode *rPoint = new TreeNode(stoi(dArray[r]));
            root->right = rPoint;
            ConductTree(rPoint, dArray, r, len);
        }
    }

    vector<string> getDataArray(string data){
        vector<string> ret;
        char dstr[1005];
        strcpy(dstr, data.c_str());
        char *p = strtok(dstr, ",");
        while(p){
            ret.push_back(string(p));
            p = strtok(NULL, ",");
        }
        return ret;
    }

    TreeNode * deserialize(string &data) {
        // write your code here
        //string -> string array
        vector<string> dArray = getDataArray(data);

        int len = dArray.size();
        TreeNode * root = NULL;
        if(len>0)
            root = new TreeNode(stoi(dArray[0]));

        ConductTree(root,dArray,0,len);
        return root;
    }
};


int main() {

//    {"1,2,#,1"}   {"1,2,3,#,4,#,#,#,#,5,6"} {"3,9,2,#,#,5,7"} {"3,9,20,#,#,1500,700"} {"3,9,20,#,#,15,7"}

    string str = {"3,9,20,#,#,1500,700"};


    TreeNode * root = Solution().deserialize(str);

    string res = Solution().serialize(root);
    return 0;
}

四、问题记录

  1. Segmentation fault (core dumped)
    这个问题主要是由于使用了野指针的原因。例如,已知p=NULL。
    那么调用 p->left或者p->right的时候,就会出错,因为”p->”这个相当于程序去找这个地址,那么找不到的话,就会报“段错误”。
    主要我序列化code的时候,想把空的节点标为“#”,后来想想不同访问空的节点,我只用在最后,遍历一下序列化的字符串,把未访问的值标记为“#”就行啦。
  2. char s[1000]={}
    这个初始化操作,会把s为首的内存,后面1000的值都标记为’\0’,即s[i]=’\0’,0<=i<=999.
  3. char s[] 转string。

    char s[1005] = {"012"};
    s[4] = '4';
    s[5] = '5';
    
    string str = s; // str = "012"
    因为s[3] = '\0',所以char s[]转String的时候,碰到第一个'\0'
    的时候,就认为字符串结束了。
  4. string str 转char s[]

    (JAVA中)由于string是个常量对象,所以string的值是不能修改的。
    而C++中的string是可变的!
    str.c_str()和str.data()都能得到string的值,二者没有太大区别。但是这两个返回的值都不能直接获得,我们看c_str()的定义,const char *c_str(); c_str()返回的是一个临时指针,不能对其进行操作。
    正确的操作方式:
    string str = "123";
    char s[1005];
    strcpy(s, str.c_str());
    
  5. char s[] 做split操作:

     首先,string的函数中也没有split操作,但是有个函数strtok可以对char s[]做split操作。
     测试代码如下:
        char s[1005] = {"1,2,3,!,!,4,50"};
        char sArr[50][1005];
        char *tmp;
        char *p = strtok_r(s, ",",&tmp);
        int cnt=0;
        while(p){
            strcpy(sArr[cnt++],p);
            printf("%s %s\n",p,tmp);
            p = strtok_r(NULL, ",", &tmp);
        }
    
    返回结果:
    1 2,3,!,!,4,50
    2 3,!,!,4,50
    3 !,!,4,50
    ! !,4,50
    ! 4,50
    4 50
    50 (null)
  6. 字符串拼接:
方法一:snprintf()函数
    s[10005];
    len = snprintf(s+s_len, 100, "%s,", "#");
    第一个参数是写入的起始地址;
    第二个参数是写入的最大长度;
    第三个参数是写入格式;
    第4个参数是写入内容;
    返回值是写入的真实长度。
     int val[] = {1,2,3,0,0,4,50}
     char s[10005]= {};
     int s_len = 0;
     for(int i=0; i<=maxNode; i++) {
         int len;
         if (!val[i])
             len = snprintf(s+s_len, 100, "%s,", "#");
         else
             len = snprintf(s+s_len, 100, "%d,", val[i]);
         s_len += len;
     }
    s[s_len] = '\0'
    //s = "123##450";

方法二:c++, string 重载了“+”
    string q1 = "123";
    string q2 = "av";
    char q3[100] = {"qq"};
    string q4 = "";

    q4 = q1+q2+q3 ; // 123avqq

方法三:c, strcat()函数
    char p1[100] = {"abc"};
    char p2[100] = {"123"};
    strcat(p1,p2); // p1: abc123

7.字符串排序

//使用<algorithm>里面的sort函数,这个sort可以对任何数组排序,前两个参数分别是 数组的起止位置,第三个参数是排序方式
string s="123456123";
sort(s.begin(), s.end()); //s: 112233456

//倒序
bool cmp(char x, char y){
    return x>y;
}
sort(s.begin(), e.end(), cmp); //s: 654332211

8.c中字符串操作函数:

strlen
strcmp ; strcmp(s1, s2),实际上是 p = s1-s2; 所以p<0,s1<s2, p==0,s1==s2, p>0,s1>s2;
strcat
strcpy
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值