(引用传递与地址传递)牛客剑指Offer面试题37:序列化二叉树

题目描述

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

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

思路

1.两个主函数分别调用两个实现序列化和反序列化的函数,序列化实现后将str序列元素逐个放入题干要求类型的数组array之中并返回结果;反序列化实现后返回二叉树根节点指针.
2.序列化实现:(选用先序遍历方式)
(1)只要传入的节点非空,则将该节点的数值转化为字符类型并添加至str中,再添加分隔的","
(2)递归调用本身函数判断左子节点,递归调用本身函数判断右子节点
3.反序列化实现:
(1)判断是否到达叶节点,如果达到叶节点,str指针后移一位并退出当前函数,返回上层递归;如果未到达叶节点,判断当前字符不是分隔符"!"且不是结束符"\0"时,则完整读取该字符并转换成数值类型放入当前树的节点root中,再判断是分隔符还是结束符以决定后移游标还是停止函数.并递归调用本身函数找到左子节点和右子节点.
(2)返回重建后二叉树的根节点

注意:
1.尽量用nullptr(新标准下C++程序),NULL为过去的程序中用到的预处理变量来给指针赋值
2.C++ Primer P188
指针形参(地址传递):定义函数时形如void reset( int *ip); 调用函数时reset(&i)
引用形参:定义函数时形如void reset(int &i); 调用函数时reset(j)
3.序列化二叉树时,不需要改变原树指针的指向,因此函数参数类型为指针;
反序列化二叉树时,需要按照序列构建二叉树,每次都不断改变新节点左右指针域的指向,因此函数参数类型为二级指针

代码

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    char* Serialize(TreeNode *root) {    
        //判断有效性
        if(root == nullptr)
            return nullptr;
        //声明一个字符串存放树的节点元素
        string str;
        mySerialize(root, str);
        //声明一个字符数组存放序列化结果
        char* array = new char[str.size() + 1];
        //将字符串逐个置入字符容器中
        for(int i = 0; i < str.size() ; ++i)
        {
            array[i] = str[i];
        }
        //存放结束字符
        array[str.size()] = '\0';
        return array;
    }
    TreeNode* Deserialize(char *str) {
        //判断有效性
        if(str == nullptr)
            return nullptr;
        TreeNode* pStr = myDeserialize(&str);
        return pStr;
    }
    
private:
    //序列化二叉树
    void mySerialize(TreeNode* root, string& str)
    {
        //递归终止条件,到达叶节点时
        if(root == nullptr)
        {
            str += '#';
            return;
        }
        //树有节点存在
        //将节点值转化为string类型存入str;
        string node = to_string(root->val);
        str += node;
        str += '!';
        //递归左右子树
        mySerialize(root->left, str);
        mySerialize(root->right, str);
        
    }
    
    //反序列化二叉树
    TreeNode* myDeserialize(char** str)
    {
        //遍历至空节点时(叶节点)
        if(**str == '#')
        {
            //指针后移一位
            (*str)++;
            return nullptr;
        }
        //声明一个数字用于存放当前节点转换后的数字
        int number = 0;
        //将当前扫描到的字符串转为数字
        while(**str != '\0' && **str != '!')
        {
            number = number * 10 + ((**str) - '0');
            //游标后移,判断是否将该字符串存储完毕
            (*str)++;
        }
        //声明反序列化后二叉树的根节点并存入数据
        TreeNode* pRoot = new TreeNode(number);
        //判断退出循环的原因是因为字符串结束还是因为当前字符为!
        if(**str == '\0')
            return pRoot;
        else
            //整个字符串未扫描完,游标后移
            (*str)++;
        //重建该节点的左右子树
        pRoot->left = myDeserialize(str);
        pRoot->right = myDeserialize(str);
        //返回重建二叉树的根节点
        return pRoot;
    }
};
发布了65 篇原创文章 · 获赞 0 · 访问量 2047

猜你喜欢

转载自blog.csdn.net/ljmiiianng/article/details/103694206