2024,1.3、2.1
昨天看了树的深度,层次遍历,先序后序中序等,今天刷了几道题巩固了一下
题目如下:
题目链接:P4913 【深基16.例3】二叉树深度 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这题由于我对指针不是特别熟练,我用了结构体数组来写
以下是画出来构建的树:
思路:由题可知根节点为1,设结构体依次输入数据构建二叉树,调用函数dfs,函数内部实现树的搜索,从根节点开始搜索,先往左边搜,直到往左边的数据为0则返回,并调用dfs往其右边搜,以此类推,其中每搜索一次深度加一,并用deep标记下来,与每次搜索的深度比大小,把大值赋给deep,这样可求出树的高度。
下面是代码的实现:
#include<stdio.h>
#include<stdlib.h>
struct tree
{
int l,r;
}tree[1000005];
int deep=0;
int max(int x,int y) //函数实现比大小
{
if(x>y)
return x;
else
return y;
}
void dfs(int i,int y)
{
deep=max(deep,y);
if(tree[i].l!=0) //当有左孩子的时候继搜索左孩子
{
dfs(tree[i].l,y+1);
}
if(tree[i].r!=0 //当有右孩子的时候继搜索右孩子
{
dfs(tree[i].r,y+1);
}
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++) //由于根节点是(0,0)所以第一组数据是从一开始的
{
scanf("%d %d",&tree[i].l,&tree[i].r); //输入数据构建树
}
dfs(1,1); //1为根节点,1为此时深度为一
printf("%d",deep);
return 0;
}
二叉树的层次遍历:
运用到了队列,算法思想:
1.初始化一个辅助队列
2.根节点入队
3.若队列非空,则队头结点出队,访问该节点,并将其左、右孩子插入队尾(如果有的话)
4.重复3.直至队列为空
看一个题目,由于太长就不截下来了,上链接:P1827 [USACO3.4] 美国血统 American Heritage - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这题是一道非常经典的题目,由中序和前序找后序
以下是代码的实现:
思路(结合以下代码看):从中序字符串中找到前序字符串的首字母,那是根节点,以根节点进行左右划分,先看左边的树,左边的树同样是以上操作,直到b中的数组空了,左边已经遍历到叶子结点,return到第一个dfs的下面开始实现右边的遍历......最后也是到b为空了从第二个dfs下来,打印,注意第二个dfs开始执行时是在第一个dfs下来的长度基础上执行的
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
void dfs(string a,string b) //实现函数
{
if((int)b.size()==0) //返回条件,抽象点就如二叉树走到了叶结点无路可走后返回
{
return;
}
int f=a.find(b[0]); //找出b[0]在a中的坐标
dfs(a.substr(0,f),b.substr(1,f)); //将左边剩下的如一开始的字符串的操作
dfs(a.substr(f+1),b.substr(f+1)); //将右边剩下的如一开始的字符串的操作
printf("%c",b[0]); //结束后从输出根
}
int main()
{
char s1[30];
char s2[30];
scanf("%s",s1);
scanf("%s",s2);
dfs(s1,s2);
return 0;
}
接下来看一道由中后求前的
上链接:
P1030 [NOIP2001 普及组] 求先序排列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目:
思路(结合代码来看):由于前序遍历是根节点开始的,所以由后序遍历找根节点,打印,再根据根节点把中序遍历划分为左子树和右子树,对左子树进行一开始的操作(找其根节点,打印),直至找空了(已经没有左孩子了,就return到第二个dfs去搜其又孩子),调用第二个dfs,,,,,,再打印,这个要自己动手动脑体会一下
以下是图,更方便理解:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#include<string.h>
void dfs(string a,string b)
{
if(a.length()==0)
{
return;
}
int len=a.length(); //计算长度
char root=b[len-1]; //根节点
int pos=a.find(root); //找出根节点在a的位置
string al=a.substr(0,pos),ar=a.substr(pos+1,len-pos-1); //并将其划为左子树和右子树
string bl=b.substr(0,pos),br=b.substr(pos,len-pos-1); //b划分为左子树和右子树
printf("%c",root); //打印出根节点
dfs(al,bl); //对左子树不断的递归,直至到无左孩子
dfs(ar,br); //对右子树进行同样的操作
}
int main()
{
char a[200];
char b[200];
scanf("%s",a);
scanf("%s",b);
dfs(a,b);
return 0;
}
最后;
P1305 新二叉树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:这题要用递归来做,很显然的第一行a为根节点,由于是前序遍历所以b为左孩子,所以接下来就要搜索后面几行的数据的开头,也就是子树的根节点有无孩子,定位在第二行,b的左孩子右孩子都有则把两个孩子插入第一行b的后面,再返回到b执行下一个d,以此类推,就可以得到一个前序遍历,
注意:插入并非插入,只是为了更好的理解,代码实现的时候直接输出要插入的就行了
#include<stdio.h>
char a[30][3];
int t;
void dfs(char q)
{
if(q=='*') //没有孩子所以返回到上一步
{
return;
}
else
{
printf("%c",q); //直接打印我上述思路部分说的插入部分
for(int i=0;i<t;i++)
{
if(a[i][0]==q) //每组数据的开头,子树的根节点
{
dfs(a[i][1]); //作为左子树的根节点,继续找其子树
dfs(a[i][2]);
}
}
}
}
int main()
{
scanf("%d",&t);
for(int i=0;i<t;i++)
{
scanf("%s",a[i]); //输入数据,建树
}
dfs(a[0][0]); //从根节点开始
return 0;
}
总结:刚学难,学了四天也难