《六月集训》第十九日——二叉树(序列化)

本文介绍了如何使用前序遍历实现二叉树的序列化与反序列化,包括LeetCode中的四道相关题目,涉及节点值转换、入度出度判断及DFS算法的应用。通过实例展示了strcat(), sprintf(), atoi()的使用技巧。

前言

这是六月集训的第十九日,今日的训练内容是 二叉树

解题报告

今日的题目的主题只有一个,二叉树的序列化和反序列化。今天的题目做完感觉又是收获满满。

1.力扣331

原题链接

331. 验证二叉树的前序序列化

题目概述

序列化二叉树的一种方法是使用 前序遍历 。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录,例如 #。(详见原题)

解题思路

假如此序列可以形成二叉树的话,那必定满足,数字的结点提供了一个入度和两个出度,而 # 结点只提供了一个入度,没有出度。根结点的入度是 0,出度是 2 最终一个二叉树的出度和入度是相等的,因此可以靠统计入度和出度的大小来判断其是否为二叉树。不可能出现入度大于出度的时刻。

还需要注意一些,数字结点里面根结点是特殊的,它没有入度,因此要特殊化处理一下,给入度的初始值为 -1

源码剖析

bool isValidSerialization(char * preorder){
    int in = -1;
    int out = 0;
    int len = strlen(preorder);
    if(preorder[0]=='#'&&len!=1) return false;
    int i;
    for(i = 0;i<len-1;i++){
        if(preorder[i]==','){
            if(preorder[i-1]=='#'){
                in++;
            }else{
                in++;
                out+=2;
            }
            if(in>=out) return false;
        }
    }
    if(preorder[len-1]=='#'){
        in++;
    }else{
        in++;
        out+=2;
    }
    return in==out;
}

这里我直接使用 来判断结点内是什么,因此最后一个结点要重新判断一下。

2.力扣297

原题链接

297. 二叉树的序列化与反序列

题目概述

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

提示: 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

解题思路

有思路,但是没有想明白怎么样把整型比较方便的填入到字符串中,于是去学习了一下其他人的写法。学到了 strcat() sprintf()atoi()的用法,确实是非常的方便。因此要记录一下这几个函数的用法。

  • strcat(字符串A,"字符串B"); 将B字符串写入到A字符串的后面
  • sprintf(字符串A,"%d",数据) 将数据格式化输入到字符串A中,注意是"%d"
  • atoi(字符串) 将字符串转化为整型数据

首先是序列化二叉树的过程,这个过程我使用的是 DFS 然后将空的结点使用 # 填充,每一个结点之间使用 进行分割。知道了字符串的一些比较好用的函数之后还是比较容易写出序列化的过程的。

接下来是反序列化的过程,其实也就是一个构建二叉树的过程,首先要先考虑一下字符串的读取的问题,因为原来的结点是使用 进行分割的,因此每次读取数据之前先读取到 为止,既然传入的参数是字符串的头指针,那么就需要额外再传入一个参数用于记录一下目前的指针指向了哪里。在搞清楚了这里之后只需要正常的当做二叉树建立来写就好了。和昨天有所不同,这次的索引不需要回溯

这题中有很多的细节,很容易出错,尤其要注意好数组的初始化的问题,其他注意点等都在源码剖析的注释中写出了。

在这题中学到的印象最深的一点是,使用临时的字符串来存储信息和进行字符串和整型数据的转换。

源码剖析

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/** Encodes a tree to a single string. */
void DFS(struct TreeNode* root,char *data){         //采用前序遍历填充字符串
    if(root==NULL){
        strcat(data,"#");
        strcat(data,",");
        return ;                                   //递归出口
    }
    char tmp[10]="";
    sprintf(tmp,"%d",root->val);                   //将结点的值转化为字符串填入临时的字符串
    strcat(data,tmp);                              //将临时的字符串填入序列化字符串中
    strcat(data,",");
    DFS(root->left,data);
    DFS(root->right,data);
}

char* serialize(struct TreeNode* root) {
    char* ret = (char*)malloc(sizeof(char)*50001);
    memset(ret,'\0',sizeof(char)*50001);
    DFS(root,ret);
    return ret;
}

struct TreeNode* treebuild(char *data,int* index){             //树的构建肯定需要使用递归,用index记录下标
    if(data[*index]=='#'){                                      //如果是空结点就不需要申请内存了
        (*index)+=2;                                            //直接跳过这个结点
        return NULL;
    }
    int i = 0;
    char tmp[10]="";                                            //初始化一定不可以忘记
    while(data[*index]!=','){
        tmp[i++] = data[(*index)++];
    }
    (*index)++;                                             //这里一定要记得移动一下下标
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); //申请内存
    root->val = atoi(tmp);
    root->left=treebuild(data,index);
    root->right=treebuild(data,index);                   //注意这两行的传入参数
    return root;
}
/** Decodes your encoded data to tree. */
struct TreeNode* deserialize(char* data) {
    int index = 0;
    return treebuild(data,&index);
}

// Your functions will be called as such:
// char* data = serialize(root);
// deserialize(data);

3.力扣剑指 Offer 37. 序列化二叉树

原题链接

剑指 Offer 37. 序列化二叉树

题目概述

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

你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

提示:输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

解题思路

和上一题一模一样,直接复用一下。

源码剖析

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/** Encodes a tree to a single string. */
void DFS(struct TreeNode* root,char *data){         //采用前序遍历填充字符串
    if(root==NULL){
        strcat(data,"#");
        strcat(data,",");
        return ;                                   //递归出口
    }
    char tmp[10]="";
    sprintf(tmp,"%d",root->val);                   //将结点的值转化为字符串填入临时的字符串
    strcat(data,tmp);                              //将临时的字符串填入序列化字符串中
    strcat(data,",");
    DFS(root->left,data);
    DFS(root->right,data);
}

char* serialize(struct TreeNode* root) {
    char* ret = (char*)malloc(sizeof(char)*50001);
    memset(ret,'\0',sizeof(char)*50001);
    DFS(root,ret);
    return ret;
}

struct TreeNode* treebuild(char *data,int* index){             //树的构建肯定需要使用递归,用index记录下标
    if(data[*index]=='#'){                                      //如果是空结点就不需要申请内存了
        (*index)+=2;                                            //直接跳过这个结点
        return NULL;
    }
    int i = 0;
    char tmp[10]="";                                            //初始化一定不可以忘记
    while(data[*index]!=','){
        tmp[i++] = data[(*index)++];
    }
    (*index)++;                                             //这里一定要记得移动一下下标
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); //申请内存
    root->val = atoi(tmp);
    root->left=treebuild(data,index);
    root->right=treebuild(data,index);                   //注意这两行的传入参数
    return root;
}
/** Decodes your encoded data to tree. */
struct TreeNode* deserialize(char* data) {
    int index = 0;
    return treebuild(data,&index);
}

// Your functions will be called as such:
// char* data = serialize(root);
// deserialize(data);

4.力扣剑指 Offer II 048. 序列化与反序列化二叉树

原题链接

剑指 Offer II 048. 序列化与反序列化二叉树

题目概述

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

解题思路

和上题一样,再写一遍熟悉熟悉。

源码剖析

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/** Encodes a tree to a single string. */
void DFS(struct TreeNode* root,char* data){
    if(root==NULL){
        strcat(data,"#");
        strcat(data,",");
        return;
    }
    char tmp[10]="";
    sprintf(tmp,"%d",root->val);
    strcat(data,tmp);
    strcat(data,",");
    DFS(root->left,data);
    DFS(root->right,data);
}

char* serialize(struct TreeNode* root) {
    char* ret = (char*)malloc(sizeof(char)*50001);
    memset(ret,'\0',sizeof(char)*50001);
    DFS(root,ret);
    return ret;
}

struct TreeNode* treebuild(char *data,int *index){
    if(data[(*index)]=='#'){
        (*index)+=2;
        return NULL;
    }
    int i = 0;
    char tmp[10]="";
    while(data[(*index)]!=',') tmp[i++] = data[(*index)++];
    (*index)++;
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    root->val = atoi(tmp);
    root->left = treebuild(data,index);
    root->right = treebuild(data,index);
    return root;
}
/** Decodes your encoded data to tree. */
struct TreeNode* deserialize(char* data) {
    int index = 0;
    return treebuild(data,&index);
}

// Your functions will be called as such:
// char* data = serialize(root);
// deserialize(data);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值