2021/2/4
把前几天的二叉树的题也记录一下
1.
这题中给出我们二叉树的一个层次序列让我们,输出这颗树的后序遍历,二叉树有4种遍历
前序遍历:父节点 左孩子 右孩子
中序遍历:左孩子 父节点 右孩子
后序遍历:左孩子 右孩子 父节点
前中后就指的是父节点(根节点的位置)
层次遍历:从根节点开始,一层一层,从左往右的遍历树。
这个题中,给出我们一个层次遍历,我们就可以根据这个层次序列构造一颗树,然后再输出他的后序遍历。用层次序列构造树的话,我们可以借用队列,从根节点开始,构造。
AC代码
#include<stdio.h>
#include<stdlib.h>
int i;
typedef struct tree
{
struct tree *left;
struct tree *right;
int value;
}node;//建立一个树的结构体,包含左右子节点,和节点值
node *creat(int a[],int n)//层次的构造一颗树
{
if(a[n]==-1)//层次序列以-1结束
return NULL;
node *t,*p;
t=p=(node*)malloc(sizeof(node));
node *dl[1100];//这个队列用于存放我们构造树的时候,左右子节点,然后一直走,这样就做到了层次构造
int front,rear;
front=rear=0;
if(a[n]!=0)
{
t->value=a[n];
t->left=NULL;
t->right=NULL;//左右节点每次都要先为NULL
dl[++rear]=t;
n++;//根节点入队,n是其序列的下标
}
while(n<i)//当点取完了结束
{
p=dl[++front];//上一个节点出队
//下面是构造出队的节点的左节点,右节点
if(a[n]!=0&&n<i)//当为0的时候就代表无左节点
{
p->left=(node*)malloc(sizeof(node));
p->left->left=p->left->right=NULL;//这里左节点的左节点和右节点要为空,这样结束的时候,不会出现叶节点左右节点不为空
p->left->value=a[n];
n++;
dl[++rear]=p->left;//左节点入队
}
else {
p->left=NULL;n++;}
//下面为右节点的构造
if(a[n]!=0&&n<i)
{
p->right=(node*)malloc(sizeof(node));
p->right->left=p->right->right=NULL;
p->right->value=a[n];
n++;
dl[++rear]=p->right;
}
else {
p->right=NULL;n++;}
}
return t;//返回根节点
}
void houxu(node *t)
{
//后序遍历递归
if(t==NULL)
return;
houxu(t->left);
houxu(t->right);
printf("%d ",t->value);
}
int ceng(node *t)
{
//计算层数
if(t==NULL)
return 0;
int cengshu=1;//因为根节点也算一层,所以初值为1
int x,y,z;
x=ceng(t->left);//返回左节点的层数
y=ceng(t->right);//返回右节点的层数
z=x>y?x:y;//保存左右节点里面比较大的一个
cengshu+=z;
return cengshu;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
i=1;
int a[1100]={0};//用于保存层次序列
int cengshu=0;
node *T=(node*)malloc(sizeof(node));
while(scanf("%d",&a[i]))
{
if(a[i]==-1) break;
i++;
}
T=creat(a,1);
cengshu=ceng(T);
printf("%d ",cengshu);
houxu(T);
printf("\n");
}
}
当知道中后序的特点后,可以通过2个序列构造出这颗树,然后先序输出,,不过我们可以在找的过程中直接输出,我们构造为3个步骤,第一步找出根节点并输出,它就在后序遍历的最后一个,第二步在中序遍历中找到根节点的位置,第三步,对左右节点进行相应的操作。
AC代码
#include<stdio.h>
#include<string.h>
void fun(int aleft,int aright,int bleft,int bright,char a[],char b[])
{
if(aleft>aright||bleft>bright)//当左右节点某一个为空的时候,结束递归
return ;
printf("%c ",b[bright]);//输出父节点
int i=aleft;
while(a[i]!=b[bright])
i++;//在中序中找到父节点的位置
fun(aleft,i-2,bleft,i-aleft+bleft-2,a,b);//递归左序列
fun(i+2,aright,i-aleft+bleft,bright-2,a,b);//递归右序列
}
int main()
{
char a[1000],b[1000];
gets(a);
gets(b);
int i,j;
for(i=0;a[i]!='\0';i++);
for(j=0;b[j]!='\0';j++);//i,j定位到最后一个字符的位置
fun(0,i-1,0,j-1,a,b);
}
这题要我们利用前序序列构造一颗二叉树,利用前序的性质,最前面那个就是我们的根节点,所以我们递归大概就是
1.建根节点
2.建左节点
3.建右节点
该题中用#号标识虚节点,所以我们递归左节点完了后,他的左右节点都会为虚,我们就结束,所递归结束条件就出来了,层序遍历的话,我们可以借助队列
AC代码
#include<stdio.h>
#include<stdlib.h>
char a[2004];
int i=1;
typedef struct tree
{
struct tree *left;
struct tree *right;
char value;
}node;
node *zhaoshu()
{
node *t=(node*)malloc(sizeof(node));
char ch=a[i++];//获取根节点
if(ch!='\0')//序列结束跳出
{
if(ch!='#')//节点为虚,跳出
{
t->value=ch;
t->left=zhaoshu();//递归左节点
t->right=zhaoshu();//递归右节点
}
else return NULL;
}
return t;//返回根节点
}
void zhongxu(node *t)
{
//中序输出
if(t==NULL)
return;
zhongxu(t->left);
printf("%c",t->value);
zhongxu(t->right);
}
void houxu(node *t)
{
//后序输出
if(t==NULL)
return;
houxu(t->left);
houxu(t->right);
printf("%c",t->value);
}
void cengxu(node *t)
{
if(t==NULL)
return;
node *duilie[1100];
int front,rear;
front=rear=0;
duilie[++rear]=t;//根节点入队
while(front!=rear)//空队退出
{
node *p=(node*)malloc(sizeof(node));
p=duilie[++front];//出队
printf("%c",p->value);//输出父节点
if(p->left!=NULL) duilie[++rear]=p->left;//有左节点就递归输出左节点的
if(p->right!=NULL) duilie[++rear]=p->right;//右节点
}
}
int main()
{
while(~scanf("%s",a+1))
{
node *T;
i=1;
T=zhaoshu();//先构造出树
zhongxu(T);//中序输出
printf(" ");
houxu(T);//后序输出
printf(" ");
cengxu(T);//层序输出
printf("\n");
}
}
这题可以说结束上面那个题的分支
AC代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define maxsize 100
typedef struct tree
{
char value;
struct tree *left;
struct tree *right;
}node;
typedef struct queue
{
node *num[maxsize];
int front;
int rear;
}queue;
node *creat()
{
char ch;
node *a=(node*)malloc(sizeof(node));
ch=getchar();
if(ch!='\0')
{
if(ch!='#')
{
a->value=ch;
a->left=creat();
a->right=creat();
}
else return NULL;
}
else return a;
}
void shuchu(node *t)
{
queue q;
node *p;
q.front=q.rear=0;
q.num[++q.rear]=t;
while(q.front!=q.rear)
{
p=q.num[++q.front];
printf("%c",p->value);
if(p->left!=NULL) q.num[++q.rear]=p->left;
if(p->right!=NULL) q.num[++q.rear]=p->right;
}
}
int main()
{
node *T;
T=creat();
shuchu(T);
}
再来2个深搜
1.全排列
#include<stdio.h>
#include<string.h>
int n;
char a[15];//存储一开始需要排列的数
char re[15];//存储每一次的排列
int vis[15];//存储每一次的标记
//假设有n个字符要排列,把他们以次放到n个箱子里面
//先要检查箱子是否为空,手中还有什么字符,把他们放进并标记
//放一次要恢复最初状态,当到n+1个箱子的时候一次全排列结束
int check(int step)
{
if(step==n+1)//满足条件
return 1;
return 0;
}
void dfs(int step)//strp代表每次放的第几个箱子
{ int i;
if(check(step))//判断边界
{
for(i=1;i<=n;i++)
printf("%c",re[i]);//当step==n+1时代表一次排列完成,然后输出这个排列
printf("\n");
return ;
}
for(i=1;i<=n;i++)//尝试每一种可能
{
if(vis[i]==0)//满足check条件
{ re[step]=a[i];
vis[i]=1;//标记
dfs(step+1);//继续下一步(step+1)
vis[i]=0;//变为最初状态(回溯的时候要用到)
}
}
return ;
}
int main(void)
{
int t;
scanf("%d",&t);
getchar();
while(t--)
{
memset(a,0,sizeof(a));
memset(vis,0,sizeof(a));//对存数据的数的数组进行初始化
scanf("%s",a+1);
n=strlen(a+1);
dfs(1);//从第一个箱子开始
}
return 0;
}
//深搜模板
check(int step)
{
if()//看到没到树底
return 1;
return 0;
}
void dfs(int step)//step 代表走到了第几层树
{
if()//使用check
{
//输出这次搜索的结果
}
//尝试这一层的每一个节点
{
//判断这个节点有没有被搜索过
//如果没有那么保存在一个地方
//进行就这个节点后的下一层搜索
//当这个节点下面的分支搜索完了后,进行回溯,标记为没搜索过
}
}
int main()
{
//从第一层开始搜索
}
2.组合数
这题主要是要考虑不取这个数的情况
#include<stdio.h>
#include<string.h>
int b[100000],a[1000000];//b存储组合数
int n,m;
void dfs(int step,int num)//step记录我们这次数要取出放在的位置,num表示当前取的数
{
if(step>m)
{
for(int i=1;i<=m;i++)
printf("%d ",b[i]);
printf("\n");
return;//当step》m时表示已经去完了一次组合数
}
if(num<=n)
{
b[step]=num;
dfs(step+1,num+1);//取这个数
dfs(step,num+1);//不取这个数
}
}
int main()
{
while(scanf("%d %d",&n,&m)&&n!=0&&m!=0)
{
memset(b,0,sizeof(b));
memset(a,0,sizeof(a));
dfs(1,1);
}
}