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

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

  通俗的说就是给定一个二叉树的根节点,用某种方法将树结构的信息存到一个字符串中,并且还可以用这一个字符串还原这棵树。

  本文介绍两种方法,分别为递归法和迭代法。

剑指 Offer 37. 序列化二叉树

  

  

递归法

  • 序列化:将树信息存到一个字符串中

  将树的先序遍历结果存到字符串中,并将nullptr 用特殊符号#来表示。注意节点的值要从整型变为字符串。

在这里插入图片描述

  则存储的字符串信息为:msg = "1,2,#,#,3,4,#,#,5,#,#"

  逗号的意义时,还原串信息时作为两个节点信息的分隔符

  

  • 反序列化:通过之前存放树信息的那个字符串将树还原
细节处理,可以先把msg尾部添加一个 ',' 便于统一处理

msg中1,2,3,4都是字符,如果两位数,三位数,就是字符串。
需要先把他们翻译回整形,这样递归建树时便于处理。同时去除逗号这个对还原树操作无用信息。

特殊字符#,可以翻译成数据范围外的整型值

可以用整形数组存放处理之后的信息

则原 msg = "1,2,#,#,3,4,#,#,5,#,#," (第一步在最后加个逗号)
变为 (字符'#' 用32位极小值表示)
vector<int> msg = [1 2 -2147483648 -2147483648 3 4 -2147483648 -2147483648 5 -2147483648 -2147483648]

最后用这个msg信息开始建树即可
  • 代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if (root == nullptr)  return "#";
        return to_string(root->val) + ',' + serialize(root->left) + ',' + serialize(root->right); 
    }


    TreeNode* __deserialize(vector<int> &msg, int &ind) {
        if (msg[ind] == INT32_MIN) {
            ++ind;
            return nullptr;
        }
        TreeNode *s = new TreeNode(msg[ind++]);
        s->left = __deserialize(msg, ind);
        s->right = __deserialize(msg, ind);
        return s;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        string t;
        data += ',';
        vector<int> msg;
        for (int i = 0; data[i]; ++i) {
            if (data[i] == ',') {
                if (t == "#")  msg.push_back(INT32_MIN);
                else  msg.push_back(stoi(t));
                t = "";
                continue;
            }
            t += data[i];
        }
        int ind = 0;
        return __deserialize(msg, ind);
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));

  

  

迭代法

  • 序列化:将树信息存到一个字符串中

  用广义表的形式存放树的信息

注意:

  • 生成广义表用递归法,通过广义表还原树用迭代法

  • 广义表还原树时,不用递归(系统栈),但要手动开辟栈结构辅助

  • 相比递归法字符串的长度,广义表的长度更长。因为迭代需要存储树的回溯信息。

  • 其实空间换时间——广义表相对长一点信息(空间),递归函数调用的开销(时间)

在这里插入图片描述

  则存储的字符串信息为:msg = "1(2(,),3(4(,),5(,)))"

  

  • 反序列化:通过之前存放树信息的那个字符串将树还原
手动开辟一个栈,存放节点指针,模拟系统栈
用一个变量flag_r表示当前节点是栈顶指针(父节点)的左子树还是右子树
用一个临时字符串str存单个节点信息

'(' : 
	Ⅰ.遇到这个字符则证明要处理当前节点的子节点了,所以当前节点信息已经通过str保存完整了。
	Ⅱ.既然完整就用str这份信息新建一个树节点(转换为整型)。同时清空str
	Ⅲ.看当前新节点是哪个节点的左子树还是右子树(栈顶元素指向当前点的父节点)
	Ⅳ.将新节点压入栈中,表示要处理它的子节点了。同时flag_r = false,下一步处理左子树
	
')' : 已经处理完了当前父节点的两个孩子,栈顶元素弹出

',' : 表示要处理右孩子了,flag_r = true,并且str清空

其它:节点值的信息用str连接存下来
  • 代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if (root == nullptr)  return "";
        return to_string(root->val) + "(" + serialize(root->left) + "," + serialize(root->right) + ")";  
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        stack<TreeNode *> s;
        TreeNode *ans = nullptr;
        bool flag_r = false;
        string str;
        for (int i = 0; data[i]; ++i) {
            if (data[i] == '(') {
                TreeNode *root = new TreeNode(stoi(str));
                if (!s.empty()) {
                    if (flag_r)  s.top()->right = root;
                    else  s.top()->left = root;
                } else  ans = root;
                s.push(root);
                flag_r = false;
                str = "";
            } else if (data[i] == ')') {
                s.pop();
            } else if (data[i] == ',') {
                flag_r = true;
                str = "";
            } else str += data[i];
        }
        return ans;
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
   } else str += data[i];
        }
        return ans;
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值