剑指offer Leetcode 37.序列化二叉树

image-20201209153920882

注意:序列化和反序列化只要能可逆就行,后面可以多出几个NULL

注意:string用+= 和push_back()效率要高于 用+,用+需要创建一个新的stirng对象

序列化:层序遍历

思想:

​ 逐层写入

复杂度:

​ ●时间:遍历每一个节点:O(n)

​ ●空间:O(n),利用队列

代码:

// Encodes a tree to a single string.
    string serialize(TreeNode* root) {
    
    
        //询问面试官为空时是string是空还是有个NULL,为空则要加判root是否为空,为NULL则不用
        queue<TreeNode*>my_queue;
        my_queue.push(root);
        string str_tree;
        //层序遍历
        while(!my_queue.empty()){
    
    
            TreeNode* cur = my_queue.front();
            my_queue.pop();
            //不为空则写入
            if(cur != NULL){
    
    
                str_tree += to_string(cur->val);
                str_tree += ",";
                my_queue.push(cur->left);
                my_queue.push(cur->right);
            }
            else
                str_tree += "NULL,";
        }
        //去掉最后的逗号
        str_tree.pop_back();
        return str_tree;
    }

反序列化

思想:

​ 将string中的每个节点分隔开并放入vector<TreeNode*>,并利用vector<TreeNode*>重建

复杂度:

​ 这里获取单个字符串较为复杂,可以使用流的方式。

代码:

TreeNode* deserialize(string data) {
    
    
        if(data.size() == 0)
            return NULL;
        int size_data = data.size(); 
        //i用来遍历data
        int i = 0;
        vector<TreeNode*>vec_tree;
        //将string转为vector<TreeNode*>来存储
        while(i < size_data){
    
    
            string str_cur = "";
            while(i < size_data && data[i] != ','){
    
    
                str_cur.push_back(data[i]);
                i++;
            }
            if(str_cur == "NULL")
                vec_tree.push_back(NULL);
            else{
    
    
                TreeNode* tmp = new TreeNode(stoi(str_cur));
                vec_tree.push_back(tmp);
            }
            //跳过逗号
            i++;
        }
        //画一下就能理解这个流程,i用来遍历父节点,j用来遍历子节点
        for(int i = 0, j = 1; j < vec_tree.size(); i++){
    
    
            if(vec_tree[i] == NULL)
                continue;
            //连接左子树
            vec_tree[i]->left = vec_tree[j++];
            //连接右子树,因为j加了1,所以需要判断
            if(j < vec_tree.size())
                vec_tree[i]->right = vec_tree[j++];
        }
        return vec_tree[0];
    }

利用流序列化和反序列化

注意:

​ 这里是用空格间隔而不是用",",这样更方便获取str_cur,要用逗号序列化可以在反序列化时先把逗号转为空格

代码:

class Codec {
    
    
public:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
    
    
        ostringstream out;
        queue<TreeNode*>my_queue;
        my_queue.push(root);
        while(!my_queue.empty()){
    
    
            TreeNode* cur = my_queue.front();
            my_queue.pop();
            if(cur != NULL){
    
    
                out<<cur->val<<" ";
                my_queue.push(cur->left);
                my_queue.push(cur->right);
            }
            else
                out<<"NULL ";
        }
        return out.str();
    
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
    
    
        istringstream input(data);
        string str_cur;
        vector<TreeNode*>vec_node;
        //利用流来获取单个字符
        while(input >> str_cur){
    
    
            if(str_cur == "NULL")
                vec_node.push_back(NULL);
            else
                vec_node.push_back(new TreeNode(stoi(str_cur)));
        }                                         
        // i每往后移动一位,j移动两位,j始终是当前i的左子下标
         // 肯定是j先到达边界,所以这里判断j < vec.size()
        for (int i = 0, j = 1; j < vec_node.size(); ++i) {
    
        
            //某个NULL的下面一层还有别的节点时(类似于NULL为头节点),如[1,N,2,N,N,3,4]就需要这里的判断
            if (vec_node[i] == NULL) continue;     
            // 当前j位置为i的左子树              
            vec_node[i]->left = vec_node[j++];    
            // 当前j位置为i的右子树,j改变了,所以需要判断
            if (j < vec_node.size()) 
                vec_node[i]->right = vec_node[j++];   
        }
        return vec_node[0];
    }
};

猜你喜欢

转载自blog.csdn.net/qq_36459662/article/details/113854164