百度Intern面试题之二叉树的网络传输及恢复--二叉树的文件存储和读取
2011-03-31 19:51
435 查看
这不是我的面试题,是一个同学在百度的面试题。
要求将一颗二叉树通过网络传输到给另一个客户端,并且在该客户端恢复为原始二叉树。
这道题目可以理解为如何将一颗二叉树存储到文件中,并且读取后正确恢复。
以这样的一棵二叉树为例:
我想到了三种解决方法:
1. 二叉树补全法,将这课二叉树补全,变成一颗完全二叉树,再使用数组进行存储,写入文件中。这样做需要在节点中增加一个属性,标记是否为补全的节点。
这种方法不太合理,因为使用了补全操作,对于一颗很不规则的二叉树,将会占用非常大的存储空间,并且修改了二叉树的属性。
2. 游标实现法。定义一个新的结构体,其中的left和right指针修改为结构体在数组中的位置。
就像下面这样,数组的第一个位置表示NULL位置,剩余的存放节点,left和right分别指向左右子节点所在数组索引。这是前序遍历递归调用得到的数组。
3. 二叉树位置描述实现。同2类似,不过这里没有左右子节点的指针,而是用一个整形来描述当前节点在一颗完全二叉树中的位置。显然,在上图这样的二叉树中,节点1的位置为1,节点2的位置为2,节点3的位置为3,节点4的位置为4,节点5的位置为6,依次类推。。。
依次,可以定义一个新的结构体描述节点信息,用于存储。
于是可以前序遍历递归调用,得到这样的一个数组。
恢复的时候,查找左右子节点,只需要查找p值2倍于自身以及2倍+1于自身的节点。
下面就是对与方法3的C++源码。
这是该程序的输出结果:
要求将一颗二叉树通过网络传输到给另一个客户端,并且在该客户端恢复为原始二叉树。
这道题目可以理解为如何将一颗二叉树存储到文件中,并且读取后正确恢复。
以这样的一棵二叉树为例:
我想到了三种解决方法:
1. 二叉树补全法,将这课二叉树补全,变成一颗完全二叉树,再使用数组进行存储,写入文件中。这样做需要在节点中增加一个属性,标记是否为补全的节点。
这种方法不太合理,因为使用了补全操作,对于一颗很不规则的二叉树,将会占用非常大的存储空间,并且修改了二叉树的属性。
2. 游标实现法。定义一个新的结构体,其中的left和right指针修改为结构体在数组中的位置。
就像下面这样,数组的第一个位置表示NULL位置,剩余的存放节点,left和right分别指向左右子节点所在数组索引。这是前序遍历递归调用得到的数组。
3. 二叉树位置描述实现。同2类似,不过这里没有左右子节点的指针,而是用一个整形来描述当前节点在一颗完全二叉树中的位置。显然,在上图这样的二叉树中,节点1的位置为1,节点2的位置为2,节点3的位置为3,节点4的位置为4,节点5的位置为6,依次类推。。。
依次,可以定义一个新的结构体描述节点信息,用于存储。
typedef struct BTreeNodeFile { Element e; //节点值 Position p; //节点在完全二叉树中的位置 } BTreeNodeFile;
于是可以前序遍历递归调用,得到这样的一个数组。
恢复的时候,查找左右子节点,只需要查找p值2倍于自身以及2倍+1于自身的节点。
下面就是对与方法3的C++源码。
/* * tree.h * * Created on: 2011-3-31 * Author: boyce */ #ifndef TREE_H_ #define TREE_H_ typedef int Element; typedef struct BTreeNode{ Element e; BTreeNode *left; BTreeNode *right; }BTreeNode; typedef struct BTree{ BTreeNode *root; unsigned int count; }BTree; typedef BTreeNode* BTreeNodePtr; typedef BTree* BTreePtr; #endif /* TREE_H_ */
/*
* main.cpp
*
* Created on: 2011-3-31
* Author: boyce
*/
#include <iostream>
#include <map>
#include <stdio.h>
#include <string.h>
#include "tree.h"
using namespace std;
typedef int Position;
typedef struct BTreeNodeFile { Element e; //节点值 Position p; //节点在完全二叉树中的位置 } BTreeNodeFile;
typedef map<int, BTreeNodePtr> NodeMap;
const char fileName[] = "btree.dat";
FILE *filePtr;
void writeNode(const BTreeNodePtr btn, Position p) {
if (!btn) {
return;
}
BTreeNodeFile node;
node.e = btn->e;
node.p = p;
//写入当前节点
fwrite(&node, sizeof(node), 1, filePtr);
//写入左子树
writeNode(btn->left, 2 * p);
//写入右子树
writeNode(btn->right, 2 * p + 1);
}
void writeBTree(const BTreePtr bt) {
filePtr = fopen(fileName, "w");
fwrite(&bt->count, sizeof(bt->count), (size_t) 1, filePtr); //写入节点个数
writeNode(bt->root, 1); //写入节点
fclose(filePtr);
}
BTreePtr readBTree() {
BTreePtr bt = new BTree;
NodeMap mapNode;
BTreeNodeFile btnf;
BTreeNode *btn;
filePtr = fopen(fileName, "r");
fread(&(bt->count), sizeof(bt->count), 1, filePtr); //读入结点个数
while (fread(&btnf, sizeof(btnf), (size_t) 1, filePtr) > 0) {
btn = new BTreeNode;
btn->e = btnf.e;
mapNode.insert(NodeMap::value_type(btnf.p, btn));
}
NodeMap::iterator iter;
NodeMap::iterator iter_t;
for (iter = mapNode.begin(); iter != mapNode.end(); iter++) {
iter_t = mapNode.find(2 * iter->first);
if (iter_t != mapNode.end()) { //找到左儿子
iter->second->left = iter_t->second;
} else { //未找到左儿子
iter->second->left = NULL;
}
iter_t = mapNode.find(2 * iter->first + 1);
if (iter_t != mapNode.end()) { //找到右儿子
iter->second->right = iter_t->second;
} else { //未找到右儿子
iter->second->right = NULL;
}
}
iter_t = mapNode.find(1); //找root节点
if (iter_t != mapNode.end()) {
bt->root = iter_t->second;
}
fclose(filePtr);
return bt;
}
BTreePtr buildBTree() {
BTreePtr bt = new BTree;
BTreeNodePtr btn = new BTreeNode[9];
for (int i = 0; i < 9; i++) {
memset(&btn[i], 0, sizeof(BTreeNode));
btn[i].e = i;
}
btn[0].left = &btn[1];
btn[1].left = &btn[3];
btn[2].left = &btn[4];
btn[5].left = &btn[7];
btn[0].right = &btn[2];
btn[2].right = &btn[5];
btn[4].right = &btn[6];
btn[5].right = &btn[8];
bt->root = &btn[0];
bt->count = 9;
return bt;
}
void printSubBTree(BTreeNodePtr btn, int lvl) {
int i;
if (!btn)
return;
for (i = 0; i < lvl; i++)
printf(" ");
printf("%d/n", btn->e + 1);
printSubBTree(btn->left, lvl + 1);
printSubBTree(btn->right, lvl + 1);
}
void printBTree(BTreePtr bt) {
printSubBTree(bt->root, 0);
}
int main() {
BTreePtr bt = buildBTree();
printBTree(bt);
writeBTree(bt);
bt = readBTree();
printBTree(bt);
return 0;
}
这是该程序的输出结果:
相关文章推荐
- 百度Intern面试题之二叉树的网络传输及恢复--二叉树的文件存储和读取
- 百度Intern面试题之二叉树的网络传输及恢复--二叉树的文件存储和读取
- 百度Intern面试题之二叉树的网络传输及恢复--二叉树的文件存储和读取
- 读取网络文件并按行存储
- 百度实习生面试题-按行读取文件
- Android手机数据读写方法(内部存储、SD卡,网络加载,包内文件读取)
- 关于文件、网络传输以及内存存储的大小端问题
- java网络编程—读取html存储到文件中
- 什么是序列化?一句话:就是将java对象固化成文件存起来,这样就java对象就被固话了,可以任意的存储和网络传输了,而java对象是暂时存在内存里的,是没办法传输的,因为是虚拟的,并不是实实在在的文件
- 20.获取网络图片,将图片存储在文件,缓存中,然后先从缓存中读取,没有再从文件中读取
- 数据库中存储与读取文件
- Android文件存储--采用SharedPreferences保存用户偏好设置参数和读取设置参数
- [数据存储之四]XML文件读取
- jcifs- 读取网络共享文件图片资源
- [unity3d]网络文件本地存储的四种方式
- java tcp 网络通信--使用多线程传输文件
- java对.txt文件进行读取方法实战---室友是网络安全方向,帮他提取文件里的特定ip
- [文件] Python读取txt存储至xls
- .Net下二进制形式的文件(图片)的存储与读取
- [机器迁移]如何通过网络快速传输海量(小)文件