剑指offer面试题37:序列化二叉树

这篇博客介绍了如何使用C++实现二叉树的序列化和反序列化。通过广度优先搜索(BFS)和迭代法,将二叉树转化为字符串并重新构建回原始树结构。示例代码中使用了`ostringstream`和`istringstream`进行字符串处理,同时也提到了C++的`atoi`和`c_str`函数在转换过程中的应用。
摘要由CSDN通过智能技术生成

题目描述:

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

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

示例:输入:root = [1,2,3,null,null,4,5]  输出:[1,2,3,null,null,4,5]

C++引入了ostringstream、istringstream、stringstream这三个类,要使用他们创建对象就必须包含<sstream>这个头文件。

istringstream类用于执行C++风格的串流的输入操作。

ostringstream类用于执行C风格的串流的输出操作。

strstream类同时可以支持C风格的串流的输入输出操作。

istringstream的构造函数原形如下:

istringstream::istringstream(string str);

它的作用是从string对象str中读取字符。

#include<iostream>
#include<sstream>        //istringstream 必须包含这个头文件#include<string>
using namespace std;
int main()
{
    string str="i am a boy";
    istringstream is(str);
    string s;
    while(is>>s)
         cout<<s<<endl;
} 

输出是:

i

am

a

boy 

方法一:广度优先 + 迭代法。(层序遍历)
其实题目的意思就是写一个函数将二叉树转成字符串(字符串的形式随你定,可以是题目所给的"[1,2,3,null,null,4,5]",也可以是本文代码中"1 2 3 null null 4 5"的形式)。
然后再写一个函数将字符串成功转回一开始的二叉树,此时最后返回的二叉树必须与题目给的一模一样。

class Codec {
public:
   
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) 
    {
       if(!root){
            return ""; // 判空
        }
        ostringstream out;
        queue<TreeNode*> bfs;
        bfs.push(root);
        while(!bfs.empty())
        {
            // 迭代法
            TreeNode* temp = bfs.front();
            bfs.pop();
            if(temp)
            {
                out<< temp -> val << " ";//以空格为分隔符
                bfs.push(temp -> left);
                bfs.push(temp -> right);
            }
            else
            {
                out<< "null "; // 注意 null 后面有空格
            }
        }
        //使用str()成员函数来获取流内部缓冲的一份拷贝
        return out.str(); // out 用来将树转成字符串,元素之间用空格分隔
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data)
    {
        if(data.empty())
        {
            return nullptr; // 判空
        }
        
        istringstream input(data);//创建 istringstream 对象 input 并同时初始化,将字符串 data 进行拷贝构造
        string info;
        vector<TreeNode*> res; // res 用来将字符串里每个元素转成 TreeNode* 形式的元素
        while(input >> info) //将 input 的内容以空格为分隔符赋给 info
        {
            if(info == "null")
            { // 注意 null 后面没空格(因为空格是用来分隔字符串的,不属于字符串)
                res.push_back(nullptr);
            }
            else
            {
                res.push_back(new TreeNode(stoi(info)));
            }
        }
        int pos = 1;
        for(int i = 0; pos < res.size(); ++i)
        {
            // 本循环将 res 中的所有元素连起来,变成一棵二叉树
            if(!res[i])
            {
                continue;
            }
            res[i] -> left = res[pos++]; // pos 此时指向左子树,++后指向右子树
            if(pos < res.size())
            {
                res[i] -> right = res[pos++]; // pos 此时指向右子树,++后指向下一个节点的左子树
            }
        }
        return res[0];
    }
};

C 语言 atoi()函数

描述

C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。但不适用于string类串,可以使用string对象中的c_str()函数进行转换。

int atoi(const char *str)

返回值

该函数返回转换后的长整数,如果没有执行有效的转换,则返回零。

C++ c_str()函数
语法:  const char *c_str()
描述:**c_str()**函数返回一个指向正规c字符串的指针,内容与string串相同。将string对象转换为c中的字符串样式。
注意:c_str()函数返回的是一个指针,可以使用字符串复制函数strcpy()来操作返回的指针。

class Codec {
public:
   
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) 
    {
        if(root == NULL) return "null";
        string data;
        queue<TreeNode*> que;  //数组用于保存层序遍历的节点
        que.push(root);
        while(!que.empty())
        {
            TreeNode* node = que.front(); //取出队列的首元素
            que.pop(); //将队列的首元素出队
              
            if(node)
            {
                //data += to_string(node->val) + ','
                data.append(to_string(node->val));
                data.append(",");
                que.push(node->left);   //则将左节点入队 
                que.push(node->right); //则将右节点入队 
            } 
            else 
            {
                data.append("null,");
            }     
        }
        if(!data.empty()) data.pop_back(); //删除字符串的结束符
        //data.erase(data.size()-1,1);
        return data;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) 
    {
        TreeNode* dummy(new TreeNode(0));  //TreeNode* dummy = new TreeNode(0)
        queue<TreeNode*> que;
        que.push(dummy);
        int beg = 0, end = 0;  //用来记录字符串 data 的起始和结束下标
        bool left_side = false; //为真则建立左节点,为假则建立右节点
        
        while (beg < data.size()) 
        {
            while (end < data.size() && data[end] != ',') ++end; 
            string str = data.substr(beg, end - beg); //获取到每个节点子串
            TreeNode *node = NULL;
            //**c_str()**函数返回一个指向正规c字符串的指针,内容与string串相同。将string对象转换为c中的字符串样式。
            //C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。但不适用于string类串,可以使用string对象中的c_str()函数进行转换。
            if (str != "null") node = new TreeNode(atoi(str.c_str()));
            
            TreeNode* curr = que.front();
            if (left_side) 
            {
                curr->left = node; 
            } 
            else 
            {
                curr->right = node;
                que.pop(); //当前节点的左节点和右节点都建立好了,则将该节点出队
            }
            
            if (node) que.push(node); //若该节点不为空,则入队
            left_side = !left_side;  
            beg = ++end; //起始和结束下标指向下一个节点
        }
        
        return dummy->right;
    }
};
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) 
{
        // bfs(层序遍历)
        string res;
        if (!root) return res; //判断节点是否为空
        queue<TreeNode*> q; //将二叉树的每个节点存入队列中
        q.push(root);  //将根节点加入队列

        while (!q.empty()) {
            TreeNode* node = q.front();
            q.pop();
            if (node) {
                res += to_string(node->val) + ",";
                q.push(node->left);
                q.push(node->right);
            }
            else res += "null,";
        }
        return res.substr(0, res.size() - 1);//获取不包含结束符的子串
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if (data.empty()) return nullptr;
        vector<string> s = split(data); //将字符串data存入字符串数组容器中
        
        queue<TreeNode*> q;
        TreeNode* root = new TreeNode(stoi(s[0]));
        q.push(root);
        int i = 1;

        while (!q.empty()) {
            TreeNode* node = q.front();
            q.pop();
            if (s[i] != "null") {
                node->left = new TreeNode(stoi(s[i]));
                q.push(node->left);
            }
            ++i;
            if (s[i] != "null") {
                node->right = new TreeNode(stoi(s[i]));
                q.push(node->right);
            }
            ++i;
        }
        return root;
    }

    vector<string> split(string& s) {
        vector<string> res;
        int n = s.size();
        int i = 0;

        while (i < n) {
            int j = i + 1;
            while (j < n && s[j] != ',') ++j;
            res.push_back(s.substr(i, j - i));
            i = j + 1; // i = ++j;
        }
        return res;
    }
};

class Codec {
public:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) 
    {
        if(root == nullptr) return ""; 
        queue<TreeNode*> q;
        q.push(root);
        string ans;
        while(!q.empty())
        {
            TreeNode* t = q.front();
            q.pop();
            if(t == nullptr) //如果为空节点
            {
                ans += "#,";
            }
            else //如果不为空节点
            {
                ans += to_string(t->val) + ',';
                q.push(t->left);
                q.push(t->right);
            }
        }
        return ans;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) 
    {
        if(data.size() == 0) return nullptr;
        vector<TreeNode*> tree;
        int idx = 0; //指向字符串的下标
        while(idx < data.size())
        {
            string s = ""; //用于记录字符串的每个字符
            //用于存放字符串中的每个字符,不包含字符串
            while(data[idx] != ',')
            {
                s += data[idx];
                idx++;
            }
            if(s == "#")
            {
                tree.push_back(nullptr);
            }
            else
            {
                int t = atoi(s.c_str());
                TreeNode* node  = new TreeNode(t);
                tree.push_back(node);
            }
            idx++;
        }
        //将数组容器中的所有元素连起来,建立一颗二叉树
        int pos = 1;
        //for(int i = 0; pos < tree.size(); i++)
        for(int i = 0; i < tree.size(); i++)
        {
            if(tree[i] == nullptr) continue;//跳出本次循环,执行下一次循环
    
            tree[i]->left = tree[pos++];
            tree[i]->right = tree[pos++];
        }
        return tree[0];
    }
};
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        // 层序遍历
        if(!root) return "[]";
        string result = "[";
        queue<TreeNode*> que;
        que.push(root);
        while (!que.empty()) 
        {
            TreeNode* node = que.front();
            que.pop();
            if (node != nullptr) 
            {
                result += to_string(node->val) + ",";
                que.push(node->left);
                que.push(node->right);
            } 
            else 
            {
                result += "null,";
            }
        }
        result.erase(result.size() - 1, 1); //去除结束符
         result += "]";
        return result;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) 
    {
        // 利用队列实现层序遍历
         if (data == "[]") return nullptr;
        data.erase(0, 1);
        data.erase(data.size() - 1, 1);

        queue<TreeNode*> que;
        int i = 0;
        string str;
        while (data[i] != ',') 
        {
            str += data[i];
            ++i;
        }
        TreeNode* root = new TreeNode(stoi(str));
        que.push(root);
        ++i;
        while (!que.empty()) 
        {
            TreeNode* node = que.front();
            que.pop();
            if (data[i] != 'n') 
            {
                str.clear();
                while (data[i] != ',') 
                {
                    str += data[i];
                    ++i;
                }
                node->left = new TreeNode(stoi(str));
                que.push(node->left);
                ++i;
            } 
            else 
            {
                i += 5;
            }
            if (data[i] != 'n') 
            {
                str.clear();
                while (data[i] != ',') 
                {
                    str += data[i];
                    ++i;
                }
                node->right = new TreeNode(stoi(str));
                que.push(node->right);
                ++i;
            } 
            else 
            {
                i += 5;
            }
        } 
        return root;
    }
};

方法二:偷懒做法 

class Codec {
private:
    TreeNode* root;

public:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        this->root = root;
        return "";
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        return root;
    }
};

stol():此函数将在函数调用中作为参数提供的字符串转换为long int。它解析str并将其内容解释为指定基数的整数,并将其作为long int类型的值返回。 

class Codec {
public:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        return to_string((unsigned long)root);
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        return (TreeNode*)stol(data);
    }
};


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值