Chinaunix首页 | 论坛 | 博客
  • 博客访问: 47339
  • 博文数量: 35
  • 博客积分: 491
  • 博客等级: 下士
  • 技术积分: 285
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-12 15:37
文章分类

全部博文(35)

文章存档

2012年(8)

2011年(27)

我的朋友
最近访客

分类:

2011-10-23 10:17:21

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

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

 

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

 

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

 

 

  我想到了三种解决方法:

  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;  
  1. typedef struct BTreeNodeFile {  
  2.     Element e; //节点值   
  3.     Position p; //节点在完全二叉树中的位置   
  4. } BTreeNodeFile;  
typedef struct BTreeNodeFile { Element e; //节点值 Position p; //节点在完全二叉树中的位置 } 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. }
阅读(1068) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~