1. 程式人生 > >(二叉樹)二叉樹的序列化與反序列化

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

題目描述

序列化是將一個數據結構或者物件轉換為連續的位元位的操作,進而可以將轉換後的資料儲存在一個檔案或者記憶體中,同時也可以通過網路傳輸到另一個計算機環境,採取相反方式重構得到原資料。

請設計一個演算法來實現二叉樹的序列化與反序列化。這裡不限定你的序列 / 反序列化演算法執行邏輯,你只需要保證一個二叉樹可以被序列化為一個字串並且將這個字串反序列化為原始的樹結構。

說明: 不要使用類的成員 / 全域性 / 靜態變數來儲存狀態,你的序列化和反序列化演算法應該是無狀態的。

題目分析

題目的意思還是比較明確的,首先給定一個樹,我們需要先將樹轉化為序列(serialize),然後再將這個序列轉換為樹原本的樣子(deserialize),呼叫的形式為deserialize(serialize(root));而這中間的樹到序列、序列到樹的轉換規則由自己決定,只要最終序列化後再反序列得到的結果與最初的樹相同即可。

首先即是對樹的序列化,對樹的序列化有多種方法:前序序列、後序序列、中序序列以及層次序列,序列化的方法都是相類似的,就不多說了,以前序序列為例,即建立一個字串,對樹進行前序遍歷,並把遍歷結果存放到樹中。這裡說兩點我在這犯了的錯誤,一個是樹上每個結點並非都是個位數,因此在遍歷的時候應當將每個結點當做字串而不是當做字元進行遍歷,空節點節點當做“#”或其他標識;除此之外,字串相互之間需要有間隔符,間隔符的選取一定要注意,“-”短橫線是不行的,因為樹結點可能是負數,這樣間隔符就會與結點有衝突。

然後就是反序列化了,反序列化實際上就是根據前面得到的序列構造樹,根據前序序列構造樹是比較容易的,需要注意的是,這裡能夠光通過前序序列構造樹的原因是,在最初生成序列的時候將空節點補充為“#”,這樣得到的序列實際上是一個完全二叉樹的前序序列,完全二叉樹只需要一種序列即可。
接下來還需要考慮的是,序列中存在間隔符,因此還應當根據間隔符來將各結點值給讀出來,一個比較簡單的辦法是將各結點值按序讀出後放入佇列中,接下來以此從隊首取出資料來遞迴構建二叉樹即可。
程式碼如下:

string serialize(TreeNode* root) {      //前序遍歷構造序列,遇到空節點以“#”代替,以“*”為分隔符
        string res;
        
        if(!root)res+="#*";
        else 
        {
            res+=to_string(root->val)+"*";   
            res+=serialize(root->left);
            res+=serialize(root->right);
        }
        return res;     
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        
        queue<string>node;
        
        std::stringstream ss(data);
        std::string item;

        while (getline(ss, item, '*'))    //以“*”為終止符從ss中讀取字串到item中,每讀取一個item將其壓入佇列
        {
            node.push(item);
        }
        
        return buildTree(node); 
    }
    
    TreeNode* buildTree(queue<string>& node){     //前序序列遞迴建樹
        
        string temp=node.front();
        node.pop();
        
        if(temp=="#")return NULL;
        
        TreeNode* root=new TreeNode(stoi(temp));
        
        root->left=buildTree(node);
        root->right=buildTree(node);
        
        return root;
    }