1. 程式人生 > 實用技巧 >二叉樹的序列化與反序列化

二叉樹的序列化與反序列化

題目來源:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/ .

按照 Leetcode 的官方習慣,二叉樹的序列化邏輯是根據其「層次遍歷」序列來實現的(參考該文章),因此本文以這種方式來解題。

預備工作

對於反序列化過程,其輸入是一個字串,我們需要將其轉換為 vector<string> ,如 "1,null,2" 需要轉換為 {"1", "null", 2"} .

vector<string> split(string &data, const string &sep)
{
    size_t l = 0;
    size_t r = data.find(sep, l);
    vector<string> result;
    while (r != string::npos)
    {
        result.emplace_back(data.substr(l, r - l));
        l = r + sep.length();
        r = data.find(sep, l);
    }
    if (l < data.length())
        result.emplace_back(data.substr(l));
    return result;
}

對於 vector<string> 中的每個元素,構造一個 API,返回對應的二叉樹節點(包括空節點):

TreeNode *generateNode(const string &s)
{
    return s == NIL ? nullptr : new TreeNode(stoi(s));
}

其次,需要 2 個常量(以成員變數的形式存在),NIL 是空節點的符號表示,SEPARATOR 是序列化字串中的分隔符:

const string NIL = "null";
const string SEPARATOR = ",";

層次遍歷實現

  • 序列化

與一般的層次遍歷幾乎一樣,唯一不同的地方是:在此處,空節點 nullptr 也進入隊列當中

❗ 需要注意的是:最後一層均為葉子節點,因此它們的左右孩子均為 null ,按照 Leetcode 的要求,序列化字串中不包含這些最後一層葉子節點的孩子。

string levelSerialize(TreeNode *root)
{
    if (root == nullptr)
        return "";
    queue<TreeNode *> q;
    q.push(root);
    vector<string> result;
    while (!q.empty())
    {
        auto node = q.front();
        q.pop();
        if (node != nullptr)
        {
            result.emplace_back(to_string(node->val));
            q.push(node->left);
            q.push(node->right);
        }
        else
            result.emplace_back(NIL);
    }
    while (result.back() == NIL) result.pop_back();
    string str;
    for (auto &x : result)  str += (x + SEPARATOR);
    if (str.back() == SEPARATOR[0])  str.pop_back();
    return "[" + str + "]";
}
  • 反序列化

還是是普通的層次遍歷演算法改過來的~

TreeNode *levelDeserialize(string &data)
{
    if (data.empty())  return nullptr;
    if (data.front() == '[' && data.back() == ']')  data = data.substr(1, data.length() - 2);
    auto v = split(data, SEPARATOR);
    int idx = 0, size = v.size();
    auto root = generateNode(v[idx++]);
    assert(root != nullptr);
    queue<TreeNode *> q;
    q.push(root);
    while (!q.empty())
    {
        auto node = q.front();
        q.pop();
        if (idx < size)  node->left = generateNode(v[idx++]);
        if (idx < size)  node->right = generateNode(v[idx++]);
        if (node->left != nullptr)  q.push(node->left);
        if (node->right != nullptr) q.push(node->right);
    }
    return root;
}