二叉樹的序列化和反序列化
設計一個算法,並編寫代碼來序列化和反序列化二叉樹。將樹寫入一個文件被稱爲“序列化”,讀取文件後重建同樣的二叉樹被稱爲“反序列化”。
如何反序列化或序列化二叉樹是沒有限制的,你只需要確保可以將二叉樹序列化爲一個字符串,並且可以將字符串反序列化爲原來的樹結構。
注意事項
There is no limit of how you deserialize or serialize a binary tree, LintCode will take your output of serialize
as
the input of deserialize
, it won't check the result of serialize.
給出一個測試數據樣例, 二叉樹{3,9,20,#,#,15,7}
,表示如下的樹結構:
3
/ \
9 20
/ \
15 7
我們的數據是進行BFS遍歷得到的。當你測試結果wrong answer時,你可以作爲輸入調試你的代碼。
你可以採用其他的方法進行序列化和反序列化。
解題思想:
本題的主要思想是進行層次遍歷。
1.首先對二叉樹進行層次遍歷,對於NULL的節點用字符#表示,每一個節點直接使用,進行分割
2.所以序列化後的二叉樹輸出的字符串data應該形如:string data = "1,2,3,#,#,4,5,#,#,6,7";
3.反序列化的思想同樣是這樣,首先將string分割成一個個的節點集合vector<string> tree,對於非NULL節點插入到一個execute隊列中,插入到隊列同時刪除tree中對應節點。
4.每次處理execute隊列的隊首元素,從tree中取出前兩個元素分別作爲左右子節點,tree中刪除前兩個元素,對於不是#的元素,將其插入到execute隊列中;對於是#的元素不操作。
5.重複第4步,直到execute隊列爲空。
/**
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* This method will be invoked first, you should design your own algorithm
* to serialize a binary tree which denote by a root node to a string which
* can be easily deserialized by your own "deserialize" method later.
*/
string serialize(TreeNode *root) { //序列化
// write your code here
string data = "";
if (root == NULL)
return data;
vector<TreeNode*> queue;
queue.push_back(root);
// 將二叉樹的個節點按照從上到下、從左到有的存儲在queue中
for (int i = 0; i<queue.size(); i++) {
TreeNode* q = queue[i];
if (q == NULL)
continue;
queue.push_back(q->left);
queue.push_back(q->right);
}
for (int i = 0; i<queue.size(); i++)
{
TreeNode* tem = queue[i];
if (tem != NULL)
{
char t[256];
string s;
sprintf(t, "%d", tem->val);
s = t;
data += (s + ",");
}
else
{
data += "#,";
}
}
return data;
}
TreeNode *deserialize(string data) { //反序列化
// write your code here
if (data == "")
return NULL;
vector<string> tree = split(data, ","); //分割得到每一個節點
queue<TreeNode*> execute; //待插入子樹的節點隊列
TreeNode * root = (TreeNode*)malloc(sizeof(TreeNode));//創建根節點
root->left = root->right = NULL;
root->val = atoi(tree[0].c_str());
tree.erase(tree.begin());
TreeNode* p = root;
execute.push(p);
while (execute.size() != 0)
{
if (tree.size()<2)
break;
TreeNode* cur = execute.front();
execute.pop();
if (tree[0] != "#") //處理左子樹
{
TreeNode* tem = (TreeNode*)malloc(sizeof(TreeNode));
tem->val = atoi(tree[0].c_str());
tem->left = tem->right = NULL;
cur->left = tem;
execute.push(tem); //左節點不是NULL,所以需要插入到隊列中,準備插入其自己的左右子節點
tree.erase(tree.begin()); //刪除tree中該節點表示該節點已經處理過了
}
else
{
tree.erase(tree.begin()); //如果cur的左節點是NULL,直接刪除Tree中的該節點表示已經處理就好了。
}
if (tree[0] != "#") //處理右子樹
{
TreeNode* tem = (TreeNode*)malloc(sizeof(TreeNode));
tem->val = atoi(tree[0].c_str());
tem->left = tem->right = NULL;
cur->right = tem;
execute.push(tem);
tree.erase(tree.begin());
}
else
{
tree.erase(tree.begin());
}
}
return root;
}
};