- 题目描述
给定一组森林,编写程序生成对应的二叉树,输出这颗二叉树叶结点对应的二进制编码.规定二叉树的左边由0表示,二叉树的右边由1表示。
- 输入
输入:
N B 表示N个树,每结点最多B个分支
第2行至第N+1行,每个树的先序遍历
- 输出
每行表示一个叶结点对应的二进制编码.
- 样例输入
3 3
A B 0 0 0 C 0 0 0 D 0 0 0
E F 0 0 0 0 0
G H 0 0 0 I J 0 0 0 0 0 0
- 样例输出
0 1 1
1 0
1 1 0 1 0
题目分析:
- 首先我们需要构造多叉树,因为树的分支是根据用户输入而定的。因此需要的结构有:多叉树结点、操作多叉树的类(函数集合)。
- 在多叉树的类中,要考虑的问题是:怎么构建多叉树?怎么将多叉树转化成二叉树?
- 在多叉树转化成二叉树之后,我们将会得到多个二叉树,显然这里需要二叉树的结点结构。那么问题又来了:怎么将森林转化成为一棵二叉树呢?在非线性存储结构中如何得到叶子结点的编码呢?这里需要一个可以对二叉树进行操作的类。
- 经过上面的分析,只要把需求里面的东西实现,这道题目就迎刃而解了。
- 难点分析:多叉树的构造、多叉树转化成二叉树、森林合成一棵二叉树、链式结构二叉树叶子结点编码。
多叉树的构造:多叉树的结点结构中,指向孩子的指针应该是二级指针,它需要根据用户的输入动态分配孩子的数目。函数传入根结点,返回根结点,在函数内部使用循环对每个孩子结点进行构造即可。
多叉树转化成二叉树:这里每个结点的孩子变成二叉树中它的左节点,每个结点的兄弟变成二叉树中它的右节点。
森林合成一棵二叉树:从第一棵树开始,后面每棵树依次成为前一棵树的右孩子结点。
链式结构二叉树叶子结点编码:与数组存储的赫夫曼树不同,数组存储方式可以直接找到树的叶子结点,再通过自身的父节点回溯可求编码。在链式结构下,叶子结点的获取并不直接。因此这里采用递归的方法去找到叶子结点,巧妙之处在于函数从一开始就传入了一个空的字符串,在找到叶子结点之前,向左孩子寻找就往字符串里加‘0’,向有孩子寻找就往字符串里加‘1’。这样编码就一层层地积累起来,当找到叶子结点时,直接输出此时的字符串就是对应叶子结点的编码了。
#include<iostream>
#include<iomanip>
#include<sstream>
#include<cstring>
using namespace std;
int B;
struct BiNode{//二叉树结点
char data;
BiNode *lChild;
BiNode *rChild;
BiNode():lChild(NULL),rChild(NULL){}
};
struct TreeNode{//多叉树结点
char data;
TreeNode **child;
TreeNode(int B){
child = new TreeNode *[B];
for (int i = 0; i < B; ++i){
child[i] = NULL;
}
}
};
//操作多叉树的类
class Tree{
TreeNode *root;//多叉树的根结点
public:
Tree(){
root = CreateTree();
}
TreeNode* CreateTree();//构造树
BiNode *getBiTree(){//获取对应二叉树
return transferToBT(root);
}
BiNode *transferToBT(TreeNode *t);//转化成二叉树
};
TreeNode* Tree::CreateTree(){
TreeNode *p;
char ch;
cin >> ch;
if(ch == '0'){
p = NULL;
}else{
p = new TreeNode(B);
p->data = ch;
for (int j = 0; j < B; j++){
p->child[j] = CreateTree();
}
}
return p;
}
BiNode* Tree::transferToBT(TreeNode *t){
BiNode *p = NULL;
if(t){
p = new BiNode;
p->data = t->data;
p->lChild = transferToBT(t->child[0]);
if(p->lChild){
BiNode *q = p->lChild;
for (int i = 1; i < B; ++i){
q->rChild = transferToBT(t->child[i]);
if(q->rChild){
q = q->rChild;
}
}
}
}
return p;
}
//操作二叉树的类
class BiTree{
BiNode *root;//二叉树的根结点
void get_leaves(BiNode *t, string str){//输出叶子结点编码
if(t){
if(!t->lChild && !t->rChild){
cout << str << endl;
}
get_leaves(t->lChild, str + "0 ");
get_leaves(t->rChild, str + "1 ");
}
}
public:
void merge(BiNode **t, int N){//合并森林
root = t[0];
for (int i = 0; i < N - 1; ++i){
t[i]->rChild = t[i + 1];
}
}
void get_leavesCode(){//获取叶子编码
string str = "";
get_leaves(root, str);
}
};
int main(){
int N;
cin >> N >> B;
Tree *p = new Tree[N];//多棵树
BiNode **q = new BiNode *[N];
for (int i = 0; i < N; ++i){//获取每棵树的二叉树
q[i] = p[i].getBiTree();
}
BiTree biT;
biT.merge(q, N);
biT.get_leavesCode();
return 0;
}
- 题后总结:本题难度较大,但是经过题目的需求分析,将目标实现拆分为几个部分,发现有很多内容都已经学习过。比较难一点的就是多叉树转化二叉树,其他的依靠现有知识都可以解决。另外,在本题中比较有启示意义的就是对链式结构的二叉树求叶子结点编码,掌握这个方法对以后类似的题目会有很大的帮助。