横向打印二叉树



历届试题 横向打印二叉树  
时间限制:1.0s   内存限制:256.0MB
问题描述

二叉树可以用于排序。其原理很简单:对于一个排序二叉树添加新节点时,先与根节点比较,若小则交给左子树继续处理,否则交给右子树。

当遇到空子树时,则把该节点放入那个位置。

比如,10 8 5 7 12 4 的输入顺序,应该建成二叉树如下图所示,其中.表示空白。

...|-12
10-|
...|-8-|
.......|...|-7
.......|-5-|
...........|-4

本题目要求:根据已知的数字,建立排序二叉树,并在标准输出中横向打印该二叉树。

输入格式

输入数据为一行空格分开的N个整数。 N<100,每个数字不超过10000。

输入数据中没有重复的数字。

输出格式

输出该排序二叉树的横向表示。为了便于评卷程序比对空格的数目,请把空格用句点代替:

样例输入1
10 5 20
样例输出1
...|-20
10-|
...|-5
样例输入2
5 10 20 8 4 7
样例输出2
.......|-20
..|-10-|
..|....|-8-|
..|........|-7
5-|
..|-4
需要解决的主要问题
  • 数据储存
  • 打印规则

数据储存
使用二叉树(目前我只想到了这个)
打印规则
因为打印是先左在、右先上后下的
所以应该针对每一行进行分发现
        发现:对于一条右支,
        如果它前一层是右支,那么它并未被上一层"盖住",打印的是 "..." ;
        如果它前一层是左支,那么它被"盖住",打印的是 "..|" 。
        之后继续,如果前一层是左支,那么再前一层是右支的话才打印 “..|”。
        直到 到第一层。
        (左支同理)

        对于一行,先扫描底层(打印靠右),再扫描高层(打印靠左)。
        然而打印顺序是先左再右
        所以需要一个栈来存储数据
        或者 使用嵌套函数

        对于左右支的判断,我选择用数组 flag 记录当前状态的左右支情况。
        用 0 1 来表示左右支,下标对应层数
        但是加上需要根据数值的位数改变 '.' 的数量
        所以决定 用正负表示左右支 用flag大小表示长度

        对于遍历树,用嵌套函数可以方便的遍历两个分支。

























#include <stdio.h>
#include <stdlib.h>

#define TYPE struct NODE
TYPE
{
	TYPE *L;
	TYPE *R;
	int atom;
};

void Del(TYPE *p)
{
	if(p==NULL)return ;
	Del(p->L);
	Del(p->R);
	free(p);
}

void Add(TYPE *p, TYPE *padd)
{
	if(padd->atom < p->atom)
	{
		if(p->L!=NULL)
			Add(p->L, padd);
		else
			p->L=padd;
	}
	else
	{
		if(p->R!=NULL)
			Add(p->R, padd);
		else
			p->R=padd;
	}
}

TYPE *Create(int num)
{
	TYPE *p=(TYPE *)malloc(sizeof(TYPE));
	p->L=NULL;
	p->R=NULL;
	p->atom=num;
	return p;
}

int lenofnum(int num)
{
	if(num<10)return 1; 
	return 1+lenofnum(num/10);
}
 
int flag[100]; 

void _f_pri(int m, int mod) 
{ 
	if(m<0)return _f_pri(-m, mod);
	int z;
	for(z=0; z<m-mod; z++) 
		printf(".");
	if(mod==1)printf("|"); 
}

void _f(int level, int baseflag) 
{
	if( level<0 )return ;
	int mod=0;
	//if( baseflag==0 || ( (flag[level]>>31)^(baseflag>>31) == -1 ) )  // ? 50 10 40 20 15 22 3
	if( baseflag==0 || (flag[level]^baseflag)<0 ) 
		mod=1;
	_f(level-1, flag[level]);
	_f_pri(flag[level], mod); 
}

void deal(TYPE *p, int level)
{
	if(p==NULL)return ;
	if(p->R!=NULL)
	{
		flag[level]=((level==0)?2:3)+lenofnum(p->atom);
		deal(p->R, level+1);
	}
	if(level!=0)_f(level-1, 0); 
	if(level!=0)printf("-"); 
	printf("%d", p->atom);  
	if(p->R==NULL && p->L==NULL)printf("\n");
	else printf("-|\n"); 
	if(p->L!=NULL)
	{
		flag[level]=-((level==0?2:3)+lenofnum(p->atom)); 
		deal(p->L, level+1);
	}
}

int main()
{
	int n=0, j, temp;
	char ch;
	TYPE *proot=NULL;
	for(j=0; j<100; j++)flag[j]=0;
	do
	{
		scanf("%d%c", &temp, &ch);
		if(++n==1)proot=Create(temp);
		else Add(proot, Create(temp));
	}while(ch==' '); 
	deal(proot, 0);
	Del(proot);
	return 0;
}



历届试题 横向打印二叉树  

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来回答您的问题。 首先,按凹入表形式横向打印叉树结构是一种常用的二叉树可视化方式,可以直观地展示二叉树的结构。具体实现过程如下: 1. 定义一个结构体Node表示二叉树的节点,包含数据域和指向左右子节点的指针。 2. 定义一个函数printTree以根节点和层数为参数,用于打印叉树结构。 3. 在printTree函数中,先判断根节点是否为空,如果为空则直接返回。 4. 如果根节点不为空,则打印根节点的数据域,并将当前层数加1。 5. 递归调用printTree函数,传入左子节点和当前层数,用于打印左子树。 6. 递归调用printTree函数,传入右子节点和当前层数,用于打印右子树。 7. 在打印左右子树之前,需要根据当前层数计算出缩进量,并将缩进量作为第一个参数传入printTree函数,用于控制打印格式。 8. 在打印左右子树之后,需要将当前层数减1,以便于回溯到上一层继续打印。 下面是该算法的代码实现: ``` typedef struct Node { int data; struct Node* left; struct Node* right; } Node; void printTree(int indent, int level, Node* root) { if (root != NULL) { int i; for (i = 0; i < indent; i++) { printf(" "); } printf("%d\n", root->data); printTree(indent + 4, level + 1, root->left); printTree(indent + 4, level + 1, root->right); } } ``` 在调试该算法时,可以采用以下步骤: 1. 编写测试用例,包括多种不同的二叉树结构,例如完全二叉树、满二叉树、非完全二叉树等。 2. 运行程序,检查输出结果是否符合预期,特别要注意缩进量是否正确。 3. 如果输出结果不符合预期,可以在printTree函数中加入调试语句,例如打印当前层数、缩进量等,以便于定位问题所在。 4. 如果仍然无法定位问题,可以使用调试工具,例如GDB或Visual Studio Debugger,逐步调试程序,查看变量的值是否正确,以便于找到问题所在。 总之,按凹入表形式横向打印叉树结构是一种常用的二叉树可视化方式,可以直观地展示二叉树的结构。在调试该算法时,需要注意输出格式和缩进量的正确性,以及使用调试工具辅助定位问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值