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