P8603 [蓝桥杯 2013 国 C] 横向打印二叉树 题解
题意
给定一个数组,依次插入进排序二叉树(这玩意不是叫二叉搜索树吗)中,然后 横向 打印这棵树。
解法
二叉搜索树的部分不再多说,题目里说的很清楚了,主要是输出格式。为了方便,本人把它存进一个字符数组 mp[1010][1010],最后再输出。
样例
...|-12
10-|
...|-8-|
.......|...|-7
.......|-5-|
...........|-4
观察样例
void output(LL p, LL space);
(虽然叫 output 但它不是输出,是处理怎样输出的。)
其中 p 是当前结点的编号,space 是要输出几个空格。
为了方便,可以将结点的值转换为字符串。
string trans(LL x){
string res;
while (x > 0)
res = ((char)(x % 10 + '0')) + res, x /= 10;
return res;
}
(很简单不说了。)
再观察,可发现每一层增加的空格都是由 这个数 和 两边的 -| 与 |- 组成,要特判一下 根节点 ,因为根节点开头没有字符。
所以 增加的空格数就是:
string num = trans(val);
LL Add = (p == 1 ? 0 : 2) + (LL)num.size() + 1;
(三元运算符的意思就是如果这个是编号
由于是中序遍历,所以结构这样:
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
...
void output(LL p, LL space){
...
output(ls(p), space + Add);
....
....
output(rs(p), space + Add);
....
return ;
}
((线段树好习惯)ls(x) 是 rs(x) 同理,Add 就是刚才求出的增加空格数。)
在处理完左子树后,就该处理自己结点了。
先在全局定义一个变量 nowL,代表现在处理到第几行了。
再是一个局部变量 ind,代表 index,现在处理到这一行的第几个了,初始化为
开始我们应先输出全部的空格。
for (LL i = 1; i <= space; i ++){
if (mp[nowL][++ ind] != '|')
mp[nowL][ind] = '.';
}
关于这个 if 有什么用,暂不讨论,看下面。
再次观察样例
可发现除了根节点和叶子结点外,输出的就为 |- 加上 这个数(可以用刚才的字符串) 加上 -| 。
根节点就除去开头的 |-。
叶子结点就除去结尾的 -|。
如下:
// 根节点特判
if (p != 1){
mp[nowL][++ ind] = '|'; mp[nowL][++ ind] = '-';
}
// 输出这个数字
for (LL i = 0; i < (LL)num.size(); i ++)
mp[nowL][++ ind] = num[i];
// 叶子结点特判
if (tree[ls(p)] != -1 || tree[rs(p)] != -1)
mp[nowL][++ ind] = '-', mp[nowL][++ ind] = '|';
为了输出方便,可在结尾加上一个标识符,代表这一行结束。
mp[nowL][++ ind] = '@';
然后处理左子树(根据前面的结构代码)。
这样算完成了
最后是重头戏。
继续观察样例,可发现如果自身与子节点隔了几行,那么要在那几行加上几个 |,列的位置和自己这一行的最后那一个 | 是一样的。
这样就还要开一个数组 line[110] 表示当前结点所在的行数。
// 如果有左子树
if (tree[ls(p)] != -1){
// L 为 左子树的 行位置
LL L = line[ls(p)], now = line[p];
for (LL i = L; i >= now; i --)
mp[i][ind - 1] = '|';
}
// 如果有右子树
if (tree[rs(p)] != -1){
// R 为 右子树的 行位置
LL R = line[rs(p)], now = line[p];
for (LL i = now; i >= R; i --)
mp[i][ind - 1] = '|';
}
这样在看刚才输出空格时的 if,就明白了它是什么意思了吧,它就是 防止后面的空格把前面的 | 覆盖。
这样整个代码就差不多完成了。
其余部分不讲了。
Code
#include<bits/stdc++.h>
#define LL long long
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
#define Fcin\
ios :: sync_with_stdio(0);\
cin.tie(0); cout.tie(0)
using namespace std;
const LL N = 110;
LL n, tree[N * 4], nowL = 0, line[N * 4];
char mp[N * 10][N * 10];
void insert(LL x, LL p){
if (tree[p] == -1){
tree[p] = x;
return ;
}
if (x < tree[p])
insert(x, ls(p));
else
insert(x, rs(p));
return ;
}
string trans(LL x){
string res;
while (x > 0)
res = ((char)(x % 10 + '0')) + res, x /= 10;
return res;
}
void output(LL p, LL space){
if (tree[p] == -1)
return ;
LL val = tree[p];
string num = trans(val);
LL Add = (p == 1 ? 0 : 2) + (LL)num.size() + 1;
output(rs(p), space + Add);
++ nowL;
line[p] = nowL;
LL ind = 0;
for (LL i = 1; i <= space; i ++){
if (mp[nowL][++ ind] != '|')
mp[nowL][ind] = '.';
}
if (p != 1){
mp[nowL][++ ind] = '|'; mp[nowL][++ ind] = '-';
}
for (LL i = 0; i < (LL)num.size(); i ++)
mp[nowL][++ ind] = num[i];
if (tree[ls(p)] != -1 || tree[rs(p)] != -1)
mp[nowL][++ ind] = '-', mp[nowL][++ ind] = '|';
mp[nowL][++ ind] = '@';
output(ls(p), space + Add);
if (tree[ls(p)] != -1){
LL L = line[ls(p)], now = line[p];
for (LL i = L; i >= now; i --)
mp[i][ind - 1] = '|';
}
if (tree[rs(p)] != -1){
LL R = line[rs(p)], now = line[p];
for (LL i = now; i >= R; i --)
mp[i][ind - 1] = '|';
}
return ;
}
int main(){
memset(tree, -1, sizeof(tree));
Fcin;
LL x;
while (cin >> x){
++ n;
insert(x, 1);
}
output(1, 0);
for (LL i = 1; i <= nowL; i ++){
LL j = 1;
while (mp[i][j] != '@'){
cout << mp[i][j];
++ j;
}
cout << "\n";
}
return 0;
}