[刷题之旅no24]P1185 绘制二叉树

这道题更像一道数学题,说实话,数学规律找得越好,解题越快,其他思路倒是对解题没有什么太大的帮助吧
只要给出确定层数
那么层与层之间的高度差可以被直接计算出来
也就是每一层所在二维字符数组中的纵坐标可以被计算出来
当二叉树确定之后,如果给定确定的第几层第几个结点,也可以把这个结点的坐标计算出来
如果给定层级,也可以把这个层级的结点所影响到的范围也计算出来
这样
我们便可以根据给定的层级
建造出相应的二叉树
通过给定结点
计算出节点位置和节点的影响范围
然后把整个结点的影响范围删除,结点影响的整个范围不好计算,还是递归删除把
递归参数需要点的坐标,
如果是向下遍历,则需要见到什么删除什么
如果向上遍历,则需要遇到o就需要停止,不可以把父节点删除奥。
ok:
出现错误:没有正确打印出结点
1.数组中出现了问题,d数组的第二项没有进行预处理,而这一项不符合我们的规律
2.creatnode函数出现问题,每一层打印节点数多了,因为应该在设置过程中内层循环j<Pow(high-i),我写成了j<Pow(high)了。内层循环的变化问题,需要反思
3.creatlink函数也出现了问题
表现为没有正确的判断标记和递归情况导致出错了。
表现相当完美
现在只需要倒着打印出来就好了。
痛哭流涕!!!!!
只得了44分
经测试:错误1,对于最底层结点删除出现了问题,我delet内层的两个函数看来出现了弊端,没办法删除当前结点
错误2,cal函数出现问题。
现在是77分,还有两个测试点没有解决,看来有一个问题是数组越界了,开的不够大,过了yes
总结一下我的思路:
1.先计算,保证给出层数,可以到的纵坐标,每层第一个的横坐标,和每层之间结点之间的距离
2.读取层数,做出相应层数的完整二叉树
3.做二叉树,根据计算公式先做结点
4.把父结点的坐标,根据这个递归,把链子做出来
5.读取删除结点,转化为坐标
6.根据删除结点坐标,进行上和下递归,保证删除所有有关联的结点和链子
遇到的错误
1.没有正确地进行预处理
2.双层循环,内部循环条件需要由外部循环决定,而我设置成了定值
3.递归的时候,没有正确判断情况
4.删除函数逻辑出现问题,不可以很好地处理边界情况
5.横纵坐标写反了,数组前者是纵坐标,后者是横坐标
6.数组开小了
总归是一道很难的题(对我来说)
如果以后的我想要提升,那么看一看大佬的代码吧,但是我现在已经看不进去了。
放代码:

#include<stdio.h>
#define maxn 3000
//结构体 
typedef struct
{
	int x,y;
}Point;
Point a;
int high=0,n=0,ceng=0,cnt=0,hx[15]={0},hy[15]={0},d[15]={0};
char tree[maxn][maxn];
//hy这个数组,用于记录第k行的第一个元素的下标
//函数
void ahead();
Point cal(int height,int num);
void deletf(int x,int y);
void delets(int x,int y);
void print();
void creat(int n);
void creatnode(int n);
void creatlink(int x,int y);
void delet(int x,int y);
int Pow(int n);
int main()
{
	scanf("%d %d",&high,&n);
	ahead();
	creat(high);
	for(int i=1;i<=n;i++)//读取并删除n个结点 
	{
		scanf("%d %d",&ceng,&cnt);
		a=cal(high-ceng+1,cnt);//转化为坐标
		delet(a.x,a.y);
	}
	print();//打印这个树 
}
void ahead()
{
	hx[1]=1,hx[2]=3;
	d[1]=3,d[2]=5;
	hy[1]=1,hy[2]=3; 
	for(int i=3;i<=10;i++)//十层基础数据拿下,这里面的第一层实际上是最后一层 
	{
		d[i]=2*d[i-1]+1;
		hx[i]=(d[i-1]-1)/2+1+hx[i-1];
		hy[i]=hx[i];	
	}//预处理 
}
Point cal(int height,int num)//第几层第几个 
{
	Point a;
	if(height==1)
	{
		a.x=1;
		if(num%2==0)
		{
			a.y=3*num-1;
		}
		else
		{
			a.y=3*num-2;
		}
	}
	else
	{
		a.x=hx[height];
		a.y=hy[height]+(cnt-1)*(d[height]+1);
	}
	return a;
}
//递归删除
void delet(int x,int y)
{
	deletf(x,y);
	delets(x,y);
	tree[x][y]=' ';
	return ;
} 
void deletf(int x,int y)//一直遍历搜索,删除相连点 
{
	if(tree[x+1][y-1]=='/')//左下角是这个
	{
		x=x+1;
		y=y-1;
		while(tree[x][y]!='o')
		{
			tree[x][y]=' ';
			x=x+1;
			y=y-1;
		}
	}
	else if(tree[x+1][y+1]=='\\')
	{
		x=x+1;
		y=y+1;
		while(tree[x][y]!='o')
		{
			tree[x][y]=' ';
			x=x+1;
			y=y+1;
		}
	}
}
void delets(int x,int y)//向上,因为我的树是反过来的 
{
	if(tree[x][y]=='o')//是o,则需要判断两端子树
	{
		tree[x][y]=' ';//左上相当于左下,x-1,y-1; 
		if(tree[x-1][y-1]=='\\')//判断'\'需要写成'\\' 
		{
			delets(x-1,y-1);
		}
		if(tree[x-1][y+1]=='/')
		{
			delets(x-1,y+1);
		}
	}
	else if(tree[x][y]=='\\')
	{
		//直接删除,然后向左上方遍历即可
		tree[x][y]=' ';
		delets(x-1,y-1);
	}
	else if(tree[x][y]=='/')
	{
		tree[x][y]=' ';
		delets(x-1,y+1);
	}
	//其它一概不管
	return ; 
} 
void print()
{
	for(int i=hx[high];i>=1;i--)//一共多少层,而且从最上面开始 
	{
		for(int j=1;j<=5*Pow(high-1);j++)//一共有多少列第一层最多 
		{
			if(tree[i][j]=='o')
			{
				printf("o");
			}
			else if(tree[i][j]=='\\')
			{
				printf("/");
			}
			else if(tree[i][j]=='/')
			{
				printf("\\");
			}
			else
			{
				printf(" ");
			} 
		}
		printf("\n");
	}
}
void creat(int n)
{
	creatnode(n);
	//创造出来之后,还要把第n层的y和x求出来,也就是hx[high]和hy[high] 
	creatlink(hx[high],hy[high]);
	return ;
}
void creatnode(int n)//多打印或者少打印问题 
{
	//从第一层,开始向下打印出n个结点,其中只有第一层比较难打印
	//外层就是层数,内层循环就是结点数
	int y=1;
	for(int i=1;i<=high;i++)
	{
		y=hy[i];//y就是第i层第一个点的横坐标 
		for(int j=1;j<=Pow(high-i);j++)//记录一共打印了多少个结点
		{
			if(i==1)//第一层特殊对待
			{
				//分情况讨论,如果当前j是奇数,那么需4,如果是偶数需要加2
				tree[hx[i]][y]='o';
				if(j%2==1)
				{
					y=y+4;
				}
				else
				{
					y=y+2;
				}
			}
			else//非第一层对待 
			{
				tree[hx[i]][y]='o';
				y=y+d[i]+1;
			}
		}
	}
	return ;
}
void creatlink(int x,int y)//给入父节点坐标,开始连线
{
	if(x==1)//如果当x==1,直接完事了
	{
		return ;
	}
	if(tree[x][y]=='o')//左右生根发芽 
	{
		//先给出我们需要的,然后直接填就可以了
		tree[x-1][y-1]='\\';
		tree[x-1][y+1]='/';
		creatlink(x-1,y-1);//左上左上方应该填 
		creatlink(x-1,y+1);//右上 
	}
	if(tree[x][y]=='\\')
	{
		if(tree[x-1][y-1]!='o')
		{
			tree[x-1][y-1]='\\';
		}
		creatlink(x-1,y-1);//左上左上方应该填 
	}
	if(tree[x][y]=='/')
	{
		if(tree[x-1][y+1]!='o')
		{
			tree[x-1][y+1]='/';
		}
		creatlink(x-1,y+1);//右上 
	}
	return ;
} 
int Pow(int n)
{
	int sum=1;
	for(int i=1;i<=n;i++)
	{
		sum=sum*2;
	}
	return sum;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值