文章目錄
題目
設計一個演算法能夠實現序列化和還原序列化一棵二叉樹(注意,不是二叉搜尋樹BST)。這裡的序列化指的是將一棵二叉樹儲存到檔案中,還原序列化就是從檔案中讀取二叉樹結點值重構原來的二叉樹。
思路
前一篇文章儲存二叉搜尋樹到檔案中 解決了儲存一棵二叉搜尋樹到檔案中的問題,但是由於本題目的意思是要把一棵二叉樹儲存到檔案中並從檔案中讀出重構二叉樹。因為二叉樹不一定是二叉搜尋樹,所以前面文章中的方法不能湊效。
解法
因為二叉樹與二叉搜尋樹的性質不同,所以不能簡單的採用前面文章中的方法。不過,我們可以採用先序遍曆的思想,只是在這裡需要改動。為了能夠在重構二叉樹時結點能夠插入到正確的位置,在使用先序遍曆儲存二叉樹到檔案中的時候需要把NULL結點也儲存起來(可以使用特殊符號如“#”來標識NULL結點)。
假定二叉樹如下所示:
_30_ / \ 10 20 / / \50 45 35
則使用先序遍曆,儲存到檔案中的內容如下:
30 10 50 # # # 20 45 # # 35 # #
序列化二叉樹
先序遍曆的代碼可以完成序列化二叉樹的工作,不管你信不信,反正我是信了。代碼如下:
void writeBinaryTree(BinaryTree *p, ostream &out) //BinaryTree是二叉樹結構體,typedef struct node BinaryTree.{ if (!p) { out << "# "; } else { out << p->data << " "; writeBinaryTree(p->left, out); writeBinaryTree(p->right, out); }}
還原序列化二叉樹
從檔案中讀取二叉樹結點並重構的方法與前面相似。採用先序遍曆的思想每次讀取一個結點,如果讀取到NULL結點的標識符號“#”,則忽略它。如果讀取到結點數值,則插入到當前結點,然後遍曆左孩子和右孩子。
void readBinaryTree(BinaryTree *&p, ifstream &fin) { int token; bool isNumber; if (!readNextToken(token, fin, isNumber)) //readNextToken讀取檔案下一個值,如果是數字返回true,否則返回false return; if (isNumber) { p = newNode(token); //newNode函數建立新結點,設定data為token,left和right初始化為NULL readBinaryTree(p->left, fin); readBinaryTree(p->right, fin); }}
進一步思考
除了先序遍曆,其實還可以使用層序遍曆來序列化二叉樹。此外,本文採用先序遍曆儲存NULL結點的方法存在缺陷,因為這樣二叉樹結點不能儲存標識符。如本方法中二叉樹結點值就不能是“#”。如果要能儲存各種字元,則需要採用其他方法來實現了。不管怎樣,對於面試來講,這樣的解法已經可以過關了。
英文原文:http://www.leetcode.com/2010/09/serializationdeserialization-of-binary.html