嗯,这道题很烦人
问题描述
二叉树可以用于排序。其原理很简单:对于一个排序二叉树添加新节点时,先与根节点比较,若小则交给左子树继续处理,否则交给右子树。
当遇到空子树时,则把该节点放入那个位置。
比如,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
按题目上的说法分布做吧,先对二叉树进行构建,如下:
struct Node{
int left=0, right=0;//left和right分别是左右子树的编号
int w;//w是节点上的数
}node[N];
void push(int i, int cur)
{
if(node[i].w<node[cur].w)
{
if(node[cur].left) push(i, node[cur].left);
else node[cur].left=i;
}
else {
if(node[cur].right) push(i, node[cur].right);
else node[cur].right=i;
}
}
还是挺好弄的,没在这里下绊子(所以他就在输出上搞事了是吗)
先看一下输出,大部分都是 ‘.’ ,然后就分为数字和 ‘-’ 以及 **‘|’**这三类,而且父节点后一定跟着 ‘-|’,然后 ‘|’ 会一直延伸到其子节点所在行,子节点前一定有 ‘|-’ ,这样分析下来这个图应该清晰了吧,为了好去把这些字符加入,用char Map[110][110]
来记录这个图,然后加一些变量 int line, Leng;//line是这个点应该在第几行,Leng是这个点上数的长度
来好将特殊字符放入图中
void writele(int cnt)//计算数字长度
{
if(node[cnt].w<10) node[cnt].Leng=1;
else if(node[cnt].w<100) node[cnt].Leng=2;
else if(node[cnt].w<1000) node[cnt].Leng=3;
else if(node[cnt].w<10000) node[cnt].Leng=4;
else node[cnt].Leng=5;
}
int lc=0;
char Map[3*N][3*N];
void dfsline(int pos)//用dfs计算数字所在行
{
if(node[pos].right) dfsline(node[pos].right);
node[pos].line=lc++;
if(node[pos].left) dfsline(node[pos].left);
}
void dfs(int cur, int pos)//标记特殊字符
{
int t=node[cur].w, p2=node[cur].Leng;
for(int i=pos+p2-1; i>=pos; i--){ Map[node[cur].line][i]=t%10+'0', t/=10;}
if(node[cur].left||node[cur].right)
{
Map[node[cur].line][pos+p2]='-', Map[node[cur].line][pos+p2+1]='|';
if(node[cur].right)
{
int l2=node[node[cur].right].line;
for(int i=node[cur].line-1; i>=l2; i--)
Map[i][p2+pos+1]='|';
Map[l2][p2+pos+2]='-';
dfs(node[cur].right, pos+p2+3);
}
if(node[cur].left)
{
int l2=node[node[cur].left].line;
for(int i=node[cur].line+1; i<=l2; i++)
Map[i][p2+pos+1]='|';
Map[l2][p2+pos+2]='-';
dfs(node[cur].left, pos+p2+3);
}
}
}
然后再把 ‘.’ 放入图中,可以发现只有数字之前要填充 ‘.’ ,所以用下面的代码填充 ‘.’
for(int i=0; i<cnt; i++)//cnt是总共有多少个数的计数
for(int j=0; Map[i][j]<'0'||Map[i][j]>'9'; j++) if(Map[i][j]==0) Map[i][j]='.';
于是整理后的代码就像下面这样了,然后就能ac这道题了
#include <iostream>
using namespace std;
const int N=110;
struct Node{
int left=0, right=0;
int w,line, Leng;
}node[N];
void push(int i, int cur)
{
if(node[i].w<node[cur].w)
{
if(node[cur].left) push(i, node[cur].left);
else node[cur].left=i;
}
else {
if(node[cur].right) push(i, node[cur].right);
else node[cur].right=i;
}
}
void writele(int cnt)
{
if(node[cnt].w<10) node[cnt].Leng=1;
else if(node[cnt].w<100) node[cnt].Leng=2;
else if(node[cnt].w<1000) node[cnt].Leng=3;
else if(node[cnt].w<10000) node[cnt].Leng=4;
else node[cnt].Leng=5;
}
int cnt;
int lc=0;
char Map[3*N][3*N];
void dfsline(int pos)
{
if(node[pos].right) dfsline(node[pos].right);
node[pos].line=lc++;
if(node[pos].left) dfsline(node[pos].left);
}
void dfs(int cur, int pos)
{
int t=node[cur].w, p2=node[cur].Leng;
for(int i=pos+p2-1; i>=pos; i--){ Map[node[cur].line][i]=t%10+'0', t/=10;}
if(node[cur].left||node[cur].right)
{
Map[node[cur].line][pos+p2]='-', Map[node[cur].line][pos+p2+1]='|';
if(node[cur].right)
{
int l2=node[node[cur].right].line;
for(int i=node[cur].line-1; i>=l2; i--)
Map[i][p2+pos+1]='|';
Map[l2][p2+pos+2]='-';
dfs(node[cur].right, pos+p2+3);
}
if(node[cur].left)
{
int l2=node[node[cur].left].line;
for(int i=node[cur].line+1; i<=l2; i++)
Map[i][p2+pos+1]='|';
Map[l2][p2+pos+2]='-';
dfs(node[cur].left, pos+p2+3);
}
}
}
int main()
{
int a;
scanf("%d", &a);
node[cnt].w=a;
writele(cnt++);
while(scanf("%d", &a)!=EOF)
{
node[cnt].w=a;
push(cnt, 0);
writele(cnt++);
}
dfsline(0);
dfs(0, 0);
for(int i=0; i<cnt; i++)
for(int j=0; Map[i][j]<'0'||Map[i][j]>'9'; j++) if(Map[i][j]==0) Map[i][j]='.';
for(int i=0; i<cnt; i++)
{
int j=0;
while(Map[i][j]!=0)
cout <<Map[i][j++];
cout <<endl;
}
return 0;
}
本来差不多是一个月一篇,这个月竟然有两篇,我真勤快呢(滑稽)