from: http://blog.csdn.net/ssjhust123/article/details/7777665
題目
設計一個算法能夠實現序列化和反序列化一棵二叉樹(注意,不是二叉搜索樹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
--------------------------------------------------------------------------------------------------------------------------------------------
My thoughts
The algorithm which records every position of a null element is space costing, but it's easier to parse.
If the tradeoff is space for efficiency, why not just output "Pre-order;In-order" of the traversed binary tree, and re-generate the binary tree based on the pre-order and in-order sequence?
Refer: 二叉樹中序前序序列(或後序)求解樹