经典题目之一,二叉树的遍历和深度广度优先都相关。
一般的binary tree的serialization 和 deserialization 相对麻烦一点,因为没有多余特征可以利用。但binary search tree就有重要的大小关系可以利用。或者说,binary tree的恢复,往往需要preorder 和inorder两个序列,或者postorder和inorder。但是binary search tree只需要preorder或者postorder就行。只用这俩就是深度优先搜索了。只用level order也行,但不太方便, 因为需要额外的内存消耗,而且本质上也还是深度优先。
方法一:preorder based serialization and deserializaiton
/**
* 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) {
string res = "";
serialize_helper(root, res);
return res;
}
void serialize_helper(TreeNode* root, string &res) {
if (root == NULL) return;
res += to_string(root->val) + ' ';
serialize_helper(root->left, res);
serialize_helper(root->right, res);
return;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
TreeNode* root = NULL;
if (data.size() == 0) return root;
vector<int> num;
int i = 0;
string curr;
while (i < data.size()) {
curr.clear();
while (i < data.size() && data[i] != ' ') curr += data[i++];
num.push_back(stoi(curr));
i++;
}
deserialize_helper(root, num, 0, num.size() - 1);
return root;
}
void deserialize_helper(TreeNode* &root, vector<int> &num, int begin, int end) {
if (begin > end) return;
root = new TreeNode(num[begin]);
int i = begin + 1;
for ( ; i <= end; i++) {
if (num[i] > num[begin]) break;
}
deserialize_helper(root->left, num, begin + 1, i - 1);
deserialize_helper(root->right, num, i, end);
}
};
这里我一开始测试的时候经常在输入为空的时候出现非法内存访问的报错,因为一开始我没有特别初始化TreeNode指针,这个时候如果没有合适的默认初始化,在直接return的情况下就会报错。所以提个醒,所有的指针变量,要么初始化为NULL,要么初始化为同类型变量,不要只是定义然后还放任特殊情况下的直接return。
如果使用level order来传递,其实本质上跟上述方法一致,都是利用二叉树本身性质,但在deserialization的时候还得新建两个数组来把小于根和大于根的分开然后传递,内存消耗很严重,不推荐。
方法二:利用BST本身性质来做deserialization
这是从leetcode讨论区粘贴过来的Java solution. 看个意思就行
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
recurse(root, sb);
return sb.toString();
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
if(data.isEmpty()) return null;
String[] vals = data.split(" ");
TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
for(int i = 1; i < vals.length; i++)
insert(root, Integer.parseInt(vals[i]));
return root;
}
private void recurse(TreeNode root, StringBuilder sb) {
if(root == null) return;
sb.append(root.val + " ");
recurse(root.left, sb);
recurse(root.right, sb);
}
private void insert(TreeNode root, int val) {
TreeNode curr = root, parent = null;
while( curr != null) {
parent = curr;
curr = curr.val < val ? curr.right : curr.left;
}
if(parent.val < val)
parent.right = new TreeNode(val);
else
parent.left = new TreeNode(val);
}
}
相当于在拿到preorder的输出之后,因为本身是先根排序,又有大小关系,可以利用BST本身性质不断插入的。