这道题大体思路是:根据一棵树的深度优先遍历过程直接用左孩子右兄弟方法构造二叉树,再求出二叉树的深度。
所以这个问题被分成了两部分:根据一棵树的深度优先遍历过程直接用左孩子右兄弟方法构造二叉树;求一棵给定二叉树的深度。
后面那个问题显然更简单(好吧其实是非常简单),我们先来处理它。
查找一棵树的深度的递归计算方法比较显然:一棵树的深度=(它的所有子树深度的最大值+1),而外部节点(即树叶的不存在的两个孩子)深度定义为-1。那么伪代码就可以很简单的这样表示:
int FindLevel(BinTreeNode *root)
{
if(root == NULL) //递归出口,遇到外部节点
return -1;
return MaxInt(FindLevel(root -> GetLeftChild()), FindLevel(root -> GetRightChild())) + 1; //递归计算子树高度
}
好了我们来解决前面的问题: 根据一棵树的深度优先遍历过程直接用左孩子右兄弟方法构造二叉树
先介绍一下左孩子右兄弟方法:对于一棵树,如果要将其转换为一棵二叉树,可以这样转换:
对于二叉树中的每一个节点,它的左孩子是原来的树中的它的第一个孩子,它的右孩子是原来的树中的它的右边的兄弟。
那么对于深度优先遍历过程,我们能得到这样的规则:
当在当前节点向下遍历(d)时,遍历到的是这个节点的孩子,这时需要查找它是否有左孩子(即现在遍历到的是不是它的第一个孩子),如果没有,则这个节点是它的第一个孩子。把遍历到的这个节点设置为当前节点的左孩子。并把指针移动到新的节点上。
如果当前节点有左孩子,那么这个节点不是它的第一个孩子,现在需要把新的节点添加到当前节点孩子的兄弟上。做法就是沿着当前节点的右孩子向下查找,直到没有右孩子的节点,将新的节点设置为其右孩子。
当在当前节点向上回溯(u)时,遍历到的是这个节点的父亲,这时需要返回它的父亲。而我们知道对于右节点,返回上一层做的事情只是回到它的兄弟节点,因此需要一直向上返回直到遇到左节点向上返回的情况为止。
这样就构造出了我们需要的二叉树。
AC代码如下:
/*
ID: Moien_Podiene
LANG: C++
*/
#include <iostream>
#include <string.h>
using namespace std;
const int MAX_LEN = 32768; //遍历字符串最大长度
class BinTreeNode;
class BinTreeNode
{
public:
BinTreeNode();
BinTreeNode(BinTreeNode *, bool); //参数1:父节点,参数2:是否为左孩子
~BinTreeNode();
BinTreeNode *GetParent(); //返回当前节点的父指针
BinTreeNode *GetLeftChild(); //返回当前节点的左孩子指针
BinTreeNode *GetRightChild(); //返回当前节点的右孩子指针
BinTreeNode *SetLeftChild(BinTreeNode *); //由参数中的节点设置当前节点的左孩子,返回左孩子指针
BinTreeNode *SetRightChild(BinTreeNode *); //由参数中的节点设置当前节点的右孩子,返回右孩子指针
bool isLeft();
private:
bool left; //当前节点是否为一个节点的左孩子
BinTreeNode *parent; //当前节点的父节点
BinTreeNode *leftChild;
BinTreeNode *rightChild;
};
int MaxInt(int, int); //比较最大值
int FindLevel(BinTreeNode *); //查找以参数为根的树的深度,只有一个根的树深度为0
int main()
{
int caseNum = 1; //当前测试组编号
int treeLevel, maxTreeLevel; //树的深度,曾经达到的最大深度
int DFSLen; //深度优先遍历字符串长度
char DFS[MAX_LEN]; //深度优先遍历字符串
while(true)
{
treeLevel = 0;
maxTreeLevel = 0;
cin >> DFS;
if(DFS[0] == '#')
break;
DFSLen = strlen(DFS);
BinTreeNode *root = new BinTreeNode; //二叉树树根
BinTreeNode *binBuff = root; //当前节点
for(int i = 0; i < DFSLen; i++) //根据树的深度优先遍历建立相应的二叉树
{
if(DFS[i] == 'd')
{
treeLevel++;
if(treeLevel > maxTreeLevel)
maxTreeLevel = treeLevel;
if(binBuff -> GetLeftChild() == NULL) //没有左孩子,那么是树的第一个孩子,设置为左孩子
{
binBuff -> SetLeftChild(new BinTreeNode(binBuff, true));
binBuff = binBuff -> GetLeftChild();
continue;
}
else //有左孩子,当前节点是树的第二个及以后的孩子,向下查找没有设置右兄弟的节点,设置右兄弟
{
binBuff = binBuff -> GetLeftChild();
while(binBuff -> GetRightChild() != NULL) //向下查找直到没有设置右兄弟的节点
binBuff = binBuff -> GetRightChild();
binBuff -> SetRightChild(new BinTreeNode(binBuff, false));
binBuff = binBuff -> GetRightChild();
continue;
}
}
else
{
treeLevel--;
while(binBuff -> isLeft() == false) //向上返回父节点,如果不是左孩子那么返回的只是兄弟节点
binBuff = binBuff -> GetParent();
binBuff = binBuff -> GetParent();
continue;
}
}
cout << "Tree " << caseNum++ << ": " << maxTreeLevel << " => " << FindLevel(root) << endl;
delete root;
}
return 0;
}
BinTreeNode::BinTreeNode()
{
left = true;
parent = leftChild = rightChild = NULL;
}
BinTreeNode::BinTreeNode(BinTreeNode *node, bool aLeft)
{
left = aLeft;
parent = node;
leftChild = rightChild = NULL;
}
BinTreeNode::~BinTreeNode()
{
if(leftChild != NULL)
delete leftChild;
if(rightChild != NULL)
delete rightChild;
}
BinTreeNode *BinTreeNode::GetParent()
{
return parent;
}
BinTreeNode *BinTreeNode::GetLeftChild()
{
return leftChild;
}
BinTreeNode *BinTreeNode::GetRightChild()
{
return rightChild;
}
BinTreeNode *BinTreeNode::SetLeftChild(BinTreeNode *val)
{
leftChild = val;
return leftChild;
}
BinTreeNode *BinTreeNode::SetRightChild(BinTreeNode *val)
{
rightChild = val;
return rightChild;
}
bool BinTreeNode::isLeft()
{
return left;
}
int MaxInt(int x, int y)
{
if(x > y)
return x;
else
return y;
}
int FindLevel(BinTreeNode *root)
{
if(root == NULL) //递归出口,遇到外部节点
return -1;
return MaxInt(FindLevel(root -> GetLeftChild()), FindLevel(root -> GetRightChild())) + 1; //递归计算子树高度
}
惯例啊惯例:原题在这里~
树的转换
查看
提交
统计
提问
总时间限制:
5000ms
内存限制:
65536kB
描述
我们都知道用“左儿子右兄弟”的方法可以将一棵一般的树转换为二叉树,如:
0 0
/ | \ /
1 2 3 ===> 1
/ \ \
4 5 2
/ \
4 3
\
5
现在请你将一些一般的树用这种方法转换为二叉树,并输出转换前和转换后树的高度。
输入
输入包括多行,最后一行以一个#表示结束。
每行是一个由“u”和“d”组成的字符串,表示一棵树的深度优先搜索信息。比如,dudduduudu可以用来表示上文中的左树,因为搜索过程为:0 Down to 1 Up to 0 Down to 2 Down to 4 Up to 2 Down to 5 Up to 2 Up to 0 Down to 3 Up to 0。
你可以认为每棵树的结点数至少为2,并且不超过10000。
输出
对于每棵树,按如下格式输出转换前和转换后树的高度:
Tree t: h1 => h2
其中t是树的编号(从1开始),h1是转换前树的高度,h2是转换后树的高度。
样例输入
dudduduudu
ddddduuuuu
dddduduuuu
dddduuduuu
#
样例输出
Tree 1: 2 => 4
Tree 2: 5 => 5
Tree 3: 4 => 5
Tree 4: 4 => 4