[Data Structure] Serialization and Deserialization of Search Binary Trees (BST) and Ordinary Binary Trees
background
The structure of binary trees is often used in algorithmic problems:
struct TreeNode { TreeNode* left, right; int val; TreeNode(int newval):val(newval), left(NULL), right(NULL) {} };
To construct some test cases, some people will write code like this to build a BST:
TreeNode* p = new TreeNode(1);
p->left = new TreeNode(2);
TreeNode* p2 = p->left;
p2->left = new TreeNode(3);
...
This is either not possible or inconvenient when constructing complex use cases.In fact, there is a more convenient way to build a binary tree, I believe we have already touched on the topic related to binary trees.This can be done with a traversal sequence of two trees, such as a sequential traversal sequence and a sequential traversal sequence to construct a unique binary tree.But this is for BST only, because each element is unique, it can be determined in order of precedence.
For binary trees where elements may not be unique, such as 1,2,2, another method is used to construct them.
Serializable and Deserialize
Serialization technology can convert data objects into persistent storage or network-transferable data.The serialization method used here is:
1. Traverse the BST tree in order and then to get an array;
2. The array is then converted to a distinguishable string.
The deserialization method is:
1. Traverse the array in order and then in order according to the string;
2. Build a tree from the sequence in 1.
Array to string conversion is ignored here.
Deserialization of BST
The sequence of BST can be constructed as follows:
TreeNode* buildTree(vector<int>& P, vector<int>& T) { if (P.size() != T.size()) return NULL; int len = P.size(); TreeNode* root = helper(P, T, 0, len - 1, 0, len - 1); return root; } TreeNode* helper(vector<int>& P, vector<int>& T, int pt, int pd, int st, int ed) { if (st > ed) return NULL; TreeNode* root = new TreeNode(0); int val = P[pt], len = P.size(); for (int i = st; i <= ed; i++) { if (T[i] == val) { root->left = helper(P, T, pt + 1, pt + i - st, st, i - 1); root->val = val; root->right = helper(P, T, pt + i - st + 1, pd, i + 1, ed); break; } } return root; }
Ordinary Binary Tree
1. Level Order Traversal notation
Except for empty nodes, nodes are represented by values within the nodes, and empty nodes are represented by #
2. Serialization + Deserialization Processes and Codes
Serialization uses: a queue, traversed hierarchically, forming a string
Deserialization: parse the string into vector <int> before building the corresponding TreeNode* root
string serializeLevelTree(TreeNode* root) { if (root == NULL) return ""; queue<TreeNode*> q; q.push(root); string s; while (!q.empty()) { TreeNode* cur = q.front(); q.pop(); if (cur != NULL) { q.push(cur->left); q.push(cur->right); char val[16]; sprintf(val, "%d", cur->val); s.append(val); s.append(1, ','); } else { s.append("#,"); } } if (s.size() > 0) { s.resize(s.size() - 1); } return s; } vector<int> deserializeLevelTree(const string& s) { int size = s.size(); vector<int> vec; int val = 0, st = 0; for (int i = 0; i < size; i++) { if (s[i] == ',' && i > st) { const char* str = s.substr(st, i - st).c_str(); if (!strcmp(str, "#")) { st = i + 1; continue; } st = i + 1; val = strtol(str, NULL, 10); vec.push_back(val); } } return vec; } TreeNode* buildLevelTree(vector<int>& vec) { int size = vec.size(); if (size == 0) return NULL; vector<TreeNode*> tvec(size); for (int i = 0; i < size; i++) { if (vec[i] != -1) { tvec[i] = new TreeNode(vec[i]); } } int j = 1; for (int i = 0; j < size; i++) { if (tvec[i] != NULL) { tvec[i]->left = tvec[j++]; if (j < size) { tvec[i]->right = tvec[j++]; } } } return tvec[0]; }
References:
[1] Serialized Binary Tree (Hierarchical Traversal)
https://blog.csdn.net/wangdongli_1993/article/details/82192341
[2] Leetcode N-ary Tree Level Order Traversal