百度Intern面试题之二叉树的网络传输及恢复--二叉树的文件存储和读取

 这不是我的面试题,是一个同学在百度的面试题。

  要求将一颗二叉树通过网络传输到给另一个客户端,并且在该客户端恢复为原始二叉树。

 

  这道题目可以理解为如何将一颗二叉树存储到文件中,并且读取后正确恢复。

 

  以这样的一棵二叉树为例:

 

 

  我想到了三种解决方法:

  1. 二叉树补全法,将这课二叉树补全,变成一颗完全二叉树,再使用数组进行存储,写入文件中。这样做需要在节点中增加一个属性,标记是否为补全的节点。

  这种方法不太合理,因为使用了补全操作,对于一颗很不规则的二叉树,将会占用非常大的存储空间,并且修改了二叉树的属性。

  2. 游标实现法。定义一个新的结构体,其中的left和right指针修改为结构体在数组中的位置。

  就像下面这样,数组的第一个位置表示NULL位置,剩余的存放节点,left和right分别指向左右子节点所在数组索引。这是前序遍历递归调用得到的数组。

 

  3. 二叉树位置描述实现。同2类似,不过这里没有左右子节点的指针,而是用一个整形来描述当前节点在一颗完全二叉树中的位置。显然,在上图这样的二叉树中,节点1的位置为1,节点2的位置为2,节点3的位置为3,节点4的位置为4,节点5的位置为6,依次类推。。。

 

  依次,可以定义一个新的结构体描述节点信息,用于存储。

 

  1. typedef struct BTreeNodeFile {  
  2.     Element e; //节点值   
  3.     Position p; //节点在完全二叉树中的位置   
  4. } BTreeNodeFile;  
 

  于是可以前序遍历递归调用,得到这样的一个数组。

 

 

 

  恢复的时候,查找左右子节点,只需要查找p值2倍于自身以及2倍+1于自身的节点。

 

  下面就是对与方法3的C++源码。

 

 

  1. /* 
  2.  * tree.h 
  3.  * 
  4.  *  Created on: 2011-3-31 
  5.  *      Author: boyce 
  6.  */  
  7. #ifndef TREE_H_   
  8. #define TREE_H_   
  9. typedef int Element;  
  10. typedef struct BTreeNode{  
  11.     Element e;  
  12.     BTreeNode *left;  
  13.     BTreeNode *right;  
  14. }BTreeNode;  
  15. typedef struct BTree{  
  16.     BTreeNode *root;  
  17.     unsigned int count;  
  18. }BTree;  
  19. typedef BTreeNode* BTreeNodePtr;  
  20. typedef BTree* BTreePtr;  
  21. #endif /* TREE_H_ */  
 

 

  1. /* 
  2.  * main.cpp 
  3.  * 
  4.  *  Created on: 2011-3-31 
  5.  *      Author: boyce 
  6.  */  
  7. #include <iostream>   
  8. #include <map>   
  9. #include <stdio.h>   
  10. #include <string.h>   
  11. #include "tree.h"   
  12. using namespace std;  
  13. typedef int Position;  
  14. typedef struct BTreeNodeFile {  
  15.     Element e; //节点值   
  16.     Position p; //节点在完全二叉树中的位置   
  17. } BTreeNodeFile;  
  18. typedef map<int, BTreeNodePtr> NodeMap;  
  19. const char fileName[] = "btree.dat";  
  20. FILE *filePtr;  
  21. void writeNode(const BTreeNodePtr btn, Position p) {  
  22.     if (!btn) {  
  23.         return;  
  24.     }  
  25.     BTreeNodeFile node;  
  26.     node.e = btn->e;  
  27.     node.p = p;  
  28.     //写入当前节点   
  29.     fwrite(&node, sizeof(node), 1, filePtr);  
  30.     //写入左子树   
  31.     writeNode(btn->left, 2 * p);  
  32.     //写入右子树   
  33.     writeNode(btn->right, 2 * p + 1);  
  34. }  
  35. void writeBTree(const BTreePtr bt) {  
  36.     filePtr = fopen(fileName, "w");  
  37.     fwrite(&bt->count, sizeof(bt->count), (size_t) 1, filePtr); //写入节点个数   
  38.     writeNode(bt->root, 1); //写入节点   
  39.     fclose(filePtr);  
  40. }  
  41. BTreePtr readBTree() {  
  42.     BTreePtr bt = new BTree;  
  43.     NodeMap mapNode;  
  44.     BTreeNodeFile btnf;  
  45.     BTreeNode *btn;  
  46.     filePtr = fopen(fileName, "r");  
  47.     fread(&(bt->count), sizeof(bt->count), 1, filePtr); //读入结点个数   
  48.     while (fread(&btnf, sizeof(btnf), (size_t) 1, filePtr) > 0) {  
  49.         btn = new BTreeNode;  
  50.         btn->e = btnf.e;  
  51.         mapNode.insert(NodeMap::value_type(btnf.p, btn));  
  52.     }  
  53.     NodeMap::iterator iter;  
  54.     NodeMap::iterator iter_t;  
  55.     for (iter = mapNode.begin(); iter != mapNode.end(); iter++) {  
  56.         iter_t = mapNode.find(2 * iter->first);  
  57.         if (iter_t != mapNode.end()) { //找到左儿子   
  58.             iter->second->left = iter_t->second;  
  59.         } else {    //未找到左儿子   
  60.             iter->second->left = NULL;  
  61.         }  
  62.         iter_t = mapNode.find(2 * iter->first + 1);  
  63.         if (iter_t != mapNode.end()) { //找到右儿子   
  64.             iter->second->right = iter_t->second;  
  65.         } else {    //未找到右儿子   
  66.             iter->second->right = NULL;  
  67.         }  
  68.     }  
  69.     iter_t = mapNode.find(1); //找root节点   
  70.     if (iter_t != mapNode.end()) {  
  71.         bt->root = iter_t->second;  
  72.     }  
  73.     fclose(filePtr);  
  74.     return bt;  
  75. }  
  76. BTreePtr buildBTree() {  
  77.     BTreePtr bt = new BTree;  
  78.     BTreeNodePtr btn = new BTreeNode[9];  
  79.     for (int i = 0; i < 9; i++) {  
  80.         memset(&btn[i], 0, sizeof(BTreeNode));  
  81.         btn[i].e = i;  
  82.     }  
  83.     btn[0].left = &btn[1];  
  84.     btn[1].left = &btn[3];  
  85.     btn[2].left = &btn[4];  
  86.     btn[5].left = &btn[7];  
  87.     btn[0].right = &btn[2];  
  88.     btn[2].right = &btn[5];  
  89.     btn[4].right = &btn[6];  
  90.     btn[5].right = &btn[8];  
  91.     bt->root = &btn[0];  
  92.     bt->count = 9;  
  93.     return bt;  
  94. }  
  95. void printSubBTree(BTreeNodePtr btn, int lvl) {  
  96.     int i;  
  97.     if (!btn)  
  98.         return;  
  99.     for (i = 0; i < lvl; i++)  
  100.         printf("  ");  
  101.     printf("%d/n", btn->e + 1);  
  102.     printSubBTree(btn->left, lvl + 1);  
  103.     printSubBTree(btn->right, lvl + 1);  
  104. }  
  105. void printBTree(BTreePtr bt) {  
  106.     printSubBTree(bt->root, 0);  
  107. }  
  108. int main() {  
  109.     BTreePtr bt = buildBTree();  
  110.     printBTree(bt);  
  111.     writeBTree(bt);  
  112.     bt = readBTree();  
  113.     printBTree(bt);  
  114.     return 0;  
  115. }  
 

 

  这是该程序的输出结果:

 

  

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值