Description
二叉树的宽度指的是具有节点数目最多的那一层的节点个数。 1 / \ 2 3 / 4 答案为2, 第二层节点数最多,为2个节点。输入格式
共n行。 第一行一个整数n,表示有n个结点,编号为1至n,结点1为树根。(1<=n<=50) 第二行至第n行,每行有两个整数x和y,表示在二叉树中x为y的父节点。x第一次出现时y为左孩子输出格式
输出二叉树的宽度。输入样例
5 1 2 1 3 2 4 2 5输出样例
2
这道题从周一的实验课到周二的一整个下午,前前后后花了差不多三个半小时,才勉勉强强搞懂……这道题看起来蛮简单的,因为之前有做过二叉树的右视图,思路是有的,但就是实现不了。我大抵是个笨蛋呜呜……
在网上找了好多博主写的题解,emm,都看不太懂……
反正都看不太懂,那就干脆只找一个,弄懂为止。本题的第一个方法,参考了下面这位博主的博客。做题的时候一定要先自己想,实在想不出来再来搜题解哦!搜到题解也不能直接Ctrl + C和Ctrl + V哦,就算是抄也要自已用手打一遍哦~https://blog.csdn.net/weixin_43004206/article/details/116243987?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165095906516782184698671%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165095906516782184698671&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-3-116243987.142^v9^control,157^v4^control&utm_term=18924+%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%AE%BD%E5%BA%A6&spm=1018.2226.3001.4187https://blog.csdn.net/weixin_43004206/article/details/116243987?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165095906516782184698671%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165095906516782184698671&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-3-116243987.142%5Ev9%5Econtrol,157%5Ev4%5Econtrol&utm_term=18924+%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%AE%BD%E5%BA%A6&spm=1018.2226.3001.4187
这个挨个演算一遍挺好懂的,我在这里浅浅做个笔记叭~
首先,这个题的树吧,它的构建跟之前做的题所用的先序构建树不太一样,方法有很多。
struct node
{
int parent;//父结点
int lchild;//左孩子
int rchild;//右孩子
} tree[55];
void CreatTree(int fu,int zi)
{
tree[zi].parent=fu;//记录孩子结点的父结点,相当于一个前驱,可用来查找根结点
if(!tree[fu].lchild)
tree[fu].lchild=zi;
else
tree[fu].rchild=zi;
}
int main()
{
int i,x,y,root;
int MAX=0;
cin >> n;
for(i=1;i<n;i++)
{
cin >> x >> y;
CreatTree(x,y);
}
……
}
我的方法如上,挺好理解的应该。输入x和y,x是y的父结点,且x第一次出现时y是左孩子(即左孩子优先)。详细看请CreatTree()函数。当然,对于这一道题来说,可以不用记录孩子结点的父结点,做这一步是为了后面找根结点,但题目已经说了1为根结点。
然后用一个类似于dfs的算法来求深度。主函数中第一次递归调用kuandu(root,1),即从根结点、第一层开始。如果一个结点有左孩子,那么就进入到下一层,直到递归到一个叶子结点,然后返回,搜索上一个结点的右孩子。
void kuandu(int root,int a)
{
level[a]++;//数组level用于记录每一层的个数
//cout << a << ' '<< level[a] <<endl;
int Root;
if(tree[root].lchild)
{
Root=tree[root].lchild;
kuandu(Root,a+1);
}
if(tree[root].rchild)
{
Root=tree[root].rchild;
kuandu(Root,a+1);
}
}
第二个for循环是为了寻找根结点,上面说过,这道题已经说明1为根结点,所以第二个for循环可以不要,主函数中直接调用函数kuandu(1,1)即可。再是第三个for循环,找数组level[]的最大值。(Tips:我一开始写的是for(i=1;i<=55;i++),看出不同了吗?对,一开始是<=55,但是我的level[]数组下标是从0到54的,他到不了55,所以一直提交一直报错。也就是我们常说的数组溢出,蛮细节的,看了大半个小时我都没找到问题)
int main()
{
int i,x,y,root;
int MAX=0;
cin >> n;
for(i=1;i<n;i++)
{
cin >> x >> y;
CreatTree(x,y);
}
for(i=1;i<=n;i++)
{
if(tree[i].parent==0)
{
root=i;
break;
}
}
kuandu(root,1);//从根结点、第一层开始
for(i=1;i<55;i++)
{
MAX=max(level[i],MAX);
}
cout << MAX;
return 0;
}
方法二——也就是标程(仅用了30行,看了之后愈发觉得我笨笨的)
标程用了一个二维数组来存放这棵树。v[x][0]存放x的左孩子,v[x][1]存放x的右孩子。
int n;
cin >> n;
int i;
int x,y;
for(i=1;i<n;i++)
{
cin >> x >> y;
if(!v[x][0])
v[x][0]=y;
else
v[x][1]=y;
}
题目有提示用队列的,但是一开始被循环绕晕了,我就没能继续写下去,因为第一层1个结点、第二层最多2个结点。第三层最多4个结点,第i层最多有2^(i-1)个结点,所以我不知道怎么控制循环条件。
看了标程之后恍然大悟,这其实跟之前做过的一道题很像,没错,就是二叉树的右视图,把父结点的孩子结点写进队列后,父结点出队,直到所有结点都出队,所以循环结束的条件就是q.size()!=0。
首先,定义一个变量len,来记录当前队列长度,也就是每一层的全部结点。注意,ans=max(len,ans)要写在内层循环前面。
再来看看内层的for循环。首先,取队头元素(没有弹出),取完再弹出,然后判断其是否有左右孩子,有的话,孩子结点入队。前面讲的取完队头元素再弹出,意思就是每一次的for循环,上一层的结点都会全部出队,上一层结点的孩子结点会入队。
queue<int>q;
q.push(1);//根结点1入队
while(q.size())
{
int len=q.size();
ans=max(len,ans);
for(i=0;i<len;i++)
{
int t=q.front();
q.pop();//弹出队头元素
if(v[t][0])
q.push(v[t][0]);
if(v[t][1])
q.push(v[t][1]);
}
}
下面是两个方法的源代码。
方法一
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <malloc.h>
#include <queue>
using namespace std;
int n,level[55];
struct node
{
int parent;//父结点
int lchild;//左孩子
int rchild;//右孩子
} tree[55];
void CreatTree(int fu,int zi)
{
tree[zi].parent=fu;//记录孩子结点的父结点,相当于一个前驱,可用来查找根结点
if(!tree[fu].lchild)
tree[fu].lchild=zi;
else
tree[fu].rchild=zi;
}
void kuandu(int root,int a)
{
level[a]++;//数组level用于记录每一层的个数
//cout << a << ' '<< level[a] <<endl;
int Root;
if(tree[root].lchild)
{
Root=tree[root].lchild;
kuandu(Root,a+1);
}
if(tree[root].rchild)
{
Root=tree[root].rchild;
kuandu(Root,a+1);
}
}
int main()
{
int i,x,y,root;
int MAX=0;
cin >> n;
for(i=1;i<n;i++)
{
cin >> x >> y;
CreatTree(x,y);
}
for(i=1;i<=n;i++)
{
if(tree[i].parent==0)
{
root=i;
break;
}
}
kuandu(root,1);//从根结点、第一层开始
for(i=1;i<55;i++)
{
MAX=max(level[i],MAX);
}
cout << MAX;
return 0;
}
方法二
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <malloc.h>
#include <queue>
using namespace std;
int n,v[105][2]={'\0'},ans=1;
int main()
{
int n;
cin >> n;
int i;
int x,y;
for(i=1;i<n;i++)
{
cin >> x >> y;
if(!v[x][0])
v[x][0]=y;
else
v[x][1]=y;
}
queue<int>q;
q.push(1);//根结点1入队
while(q.size())
{
int len=q.size();
ans=max(len,ans);
for(i=0;i<len;i++)
{
int t=q.front();
q.pop();//弹出队头元素
if(v[t][0])
q.push(v[t][0]);
if(v[t][1])
q.push(v[t][1]);
}
}
cout << ans;
return 0;
}