[LeetCode] Serialize and Deserialize N-ary Tree N叉搜尋樹的序列化和去序列化
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize an N-ary tree. An N-ary tree is a rooted tree in which each node has no more than N children. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that an N-ary tree can be serialized to a string and this string can be deserialized to the original tree structure.
For example, you may serialize the following 3-ary
tree
as [1 [3[5 6] 2 4]]
. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.
Note:
N
is in the range of[1, 1000]
- Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.
這道題讓我們對N叉樹進行序列化和去序列化,序列化就是將一個數據結構或物體轉化為一個位序列,可以存進一個檔案或者記憶體緩衝器中,然後通過網路連線在相同的或者另一個電腦環境中被還原,還原的過程叫做去序列化。現在讓我們來序列化和去序列化一個二叉樹,並給了我們例子。由於我們有了之前那道Serialize and Deserialize Binary Tree對二叉樹的序列化和去序列化的基礎,那麼這道N叉樹的方法也是大同小異了。首先使用先序遍歷的遞迴解法,遞迴的寫法就十分的簡潔了,對於序列化,我們需要一個helper函式,裡面首先判斷結點,若為空,則結果res加上一個井字元,否則加上當前結點值,跟一個空格,再加上子結點的個數值,再跟一個空格。之後就是遍歷子結點了,對每個子結點都呼叫遞迴函式即可。去序列函式需要用一個字串流類來幫助讀字元,這個類是按空格來斷開字串的,所以我們在序列化的時候中間都是用的空格。我們同樣需要一個helper函式,首先讀出結點值,如果讀出了井字號,直接返回空。否則繼續讀出子結點的個數,有了結點值我們就可以新建一個結點了,同時知道了子結點的個數,那麼我們就迴圈呼叫遞迴函式相同的次數,將返回的子結點加入子結點陣列即可,參見程式碼如下:
解法一:
class Codec { public: // Encodes a tree to a single string. string serialize(Node* root) { string res; serializeHelper(root, res); return res; } void serializeHelper(Node* node, string& res) { if (!node) res += "#"; else { res += to_string(node->val) + " " + to_string(node->children.size()) + " "; for (auto child : node->children) { serializeHelper(child, res); } } } // Decodes your encoded data to tree. Node* deserialize(string data) { istringstream iss(data); return deserializeHelper(iss); } Node* deserializeHelper(istringstream& iss) { string val = "", size = ""; iss >> val; if (val == "#") return NULL; iss >> size; Node *node = new Node(stoi(val), {}); for (int i = 0; i < stoi(size); ++i) { node->children.push_back(deserializeHelper(iss)); } return node; } };
我們還可以使用層序遍歷的迭代寫法,序列化的函式相對來說好一點,還是先判空,若為空,直接返回井字號。否則就使用佇列,加入根結點,然後就進行while迴圈,先取出隊首結點,然後res加入結點值,再加入空格,加入子結點個數,再加上空格。之後再把每一個子結點都加入佇列中即可。去序列化函式稍稍複雜一些,還是要用字元流類來讀取字元,需要用兩個佇列,分別來儲存結點,和子結點個數。首先我們先取出結點值,如果是井字號,直接返回空。否則再取出子結點個數,我們先根據之前取出的結點值新建一個結點,然後加入結點佇列,把子結點個數加入個數佇列。然後就開始遍歷了,首先分別取出結點佇列和個數佇列的隊首元素,然後迴圈子結點個數次,再取出結點值,和子結點個數,如果其中某個值沒取出來,就break掉。根據取出的結點值新建一個結點,然後將結點值加入結點佇列,子結點個數加入個數佇列,然後將子結點加入子結點陣列,參見程式碼如下:
解法二:
class Codec { public: // Encodes a tree to a single string. string serialize(Node* root) { if (!root) return "#"; string res; queue<Node*> q{{root}}; while (!q.empty()) { Node *t = q.front(); q.pop(); res += to_string(t->val) + " " + to_string(t->children.size()) + " "; for (Node *child : t->children) { q.push(child); } } return res; } // Decodes your encoded data to tree. Node* deserialize(string data) { istringstream iss(data); queue<Node*> qNode; queue<int> qSize; string val = "", size = ""; iss >> val; if (val == "#") return NULL; iss >> size; Node *res = new Node(stoi(val), {}), *cur = res; qNode.push(cur); qSize.push(stoi(size)); while (!qNode.empty()) { Node *t = qNode.front(); qNode.pop(); int len = qSize.front(); qSize.pop(); for (int i = 0; i < len; ++i) { if (!(iss >> val)) break; if (!(iss >> size)) break; cur = new Node(stoi(val), {}); qNode.push(cur); qSize.push(stoi(size)); t->children.push_back(cur); } } return res; } };
類似題目:
參考資料: