试题 历届试题 横向打印二叉树

资源限制
时间限制: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 

这题初看,除了知道这些数值是自顶向下递减的,其他没什么头绪,然后看了网上的一些代码,但是本人的代码阅读能力有些差,还是实力太差了,所以愣是看不大懂,不过总算也提取了些重要的信息.

1.声明一个变量用于存储根节点的值;

2.开辟两个数组L[]和R[]分别用于存储每个节点的左子树和右子树的信息;

3.写一个add()函数处理添加新节点的操作.

 了解了这些之后我就开始自己在纸上写写画画,既然知道了节点的行号,那么也要确定其列号才行,然后发现除了根节点列号为0,每个节点的列号正好是其父节点的列号+父节点的数值长度+3(这个3即"-|-"的长度),于是我开辟了一个数组pos[]用于记录节点的列号,数组len[]记录数字长度.  于是写出如下(有bug的)代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <string>
 6 #include <cmath>
 7 #include <algorithm>
 8 #define INF 0x3f3f3f3f
 9 #define zero 1e-7
10 
11 using namespace std;
12 typedef long long ll;
13 const ll mod=1e9+7;
14 const ll max_n=105;
15 
16 int a[max_n]={0};//记录输入的数字 
17 int L[max_n]={0};//记录节点的左子树 
18 int R[max_n]={0};//记录节点的右子树 
19 int pos[max_n]={0};//记录节点的列号 
20 int len[max_n]={0};//记录数字的长度 
21 
22 //添加新节点 
23 void add(int r, int x) { 
24     if(x<r) {//若x<r则将x交给r的左子树处理 
25         if(!L[r]) {//若r的左子树为空,则将x放入这个位置
26             L[r]=x;
27             pos[x]=pos[r]+len[r]+3;//x的列号,3是"-|-"的长度 
28         }
29         else {
30             add(L[r], x);
31         }
32     }
33     else {//否则将x交给r的左子树处理 
34         if(!R[r]) {
35             R[r]=x;
36             pos[x]=pos[r]+len[r]+3;
37         }
38         else {
39             add(R[r], x);
40         }
41     }
42 }
43 
44 int main() {
45     int k=0;//k记录输入数字的个数
46     int root;//记录根节点的值 
47     while(cin>>a[k]) {
48         int temp=a[k];
49         while(temp) {//计算数字a[k]的长度 
50             len[a[k]]++;
51             temp/=10;
52         }
53         if(!k) {//第一个输入的数字是根节点 
54             root=a[k];
55             pos[a[k]]=0;
56         }
57         else {
58             add(root, a[k]);
59         }
60         k++;
61     }
62     sort(a, a+k, greater<int>());//按降序排列,由排序二叉树的特性可知,自顶往下数值越小 
63     for(int i=0; i<k; i++) {//打印输出 
64         for(int j=0; j<pos[a[i]]-2; j++) {
65             cout<<'.';
66         }
67         if(a[i]!=root) cout<<"|-";
68         cout<<a[i];
69         if(L[a[i]] || R[a[i]]) cout<<"-|";
70         cout<<endl;
71     }
72     return 0;
73 }

运行之后输出是这样的(Ctrl+Z+回车 结束输入得结果)——

没错,漏了好几个'|',因为我只在节点前面添加了'|',而忽略了每个父节点从其右子树到左子树的纵向之间的'|',这可如何是好,想了想,于是我开辟了一个二维数组mp[][]用于记录数字前面的'.','|' 和'-',并写了两个循环,一个用于填满每行数字前面的'.','|'和'-',一个用于专门处理每个父节点从其右子树到左子树的纵向之间的'|',也就是64~89行的代码,当然打印输出那里也改了一下,以下是修改后的AC代码——

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <string>
 6 #include <cmath>
 7 #include <algorithm>
 8 #define INF 0x3f3f3f3f
 9 #define zero 1e-7
10 
11 using namespace std;
12 typedef long long ll;
13 const ll mod=1e9+7;
14 const ll max_n=105;
15 
16 char mp[max_n][max_n];//记录数字前面的'.','|' 和'-' 
17 int a[max_n]={0};//记录输入的数字 
18 int L[max_n]={0};//记录节点的左子树 
19 int R[max_n]={0};//记录节点的右子树 
20 int pos[max_n]={0};//记录节点的列号 
21 int len[max_n]={0};//记录数字的长度 
22 
23 //添加新节点 
24 void add(int r, int x) { 
25     if(x<r) {//若x<r则将x交给r的左子树处理 
26         if(!L[r]) {//若r的左子树为空,则将x放入这个位置 
27             L[r]=x;
28             pos[x]=pos[r]+len[r]+3;//x的列号,3是"-|-"的长度 
29         }
30         else {
31             add(L[r], x);
32         }
33     }
34     else {//否则将x交给r的左子树处理 
35         if(!R[r]) {
36             R[r]=x;
37             pos[x]=pos[r]+len[r]+3;
38         }
39         else {
40             add(R[r], x);
41         }
42     }
43 }
44 
45 int main() {
46     int k=0;//k记录输入数字的个数 
47     int root;//记录根节点的值 
48     while(cin>>a[k]) {
49         int temp=a[k];
50         while(temp) {//计算数字a[k]的长度 
51             len[a[k]]++;
52             temp/=10;
53         }
54         if(!k) {//第一个输入的数字是根节点 
55             root=a[k];
56             pos[a[k]]=0;
57         }
58         else {
59             add(root, a[k]);
60         }
61         k++;
62     }
63     sort(a, a+k, greater<int>());//按降序排列,由排序二叉树的特性可知,自顶往下数值越小 
64     //这个循环是将每行的数字前面填满'.','|'和'-' 
65     for(int i=0; i<k; i++) {
66         int j;
67         for(j=0; j<pos[a[i]]-2; j++) {
68             mp[i][j]='.';
69         }
70         mp[i][j++]='|';
71         mp[i][j]='-';
72     }
73     //这个循环是处理每个节点从其右子树到左子树的纵向之间的'|' 
74     for(int i=0; i<k; i++) {
75         int temp=pos[a[i]]+len[a[i]]+1;//这是节点a[k]右边的'|'的列号 
76         if(R[a[i]]) {//若该节点有右子树 
77             for(int j=i-1; ; j--) {//往上 
78                 if(a[j]>=R[a[i]]) break;
79                 mp[j][temp]='|';
80             }
81         }
82         if(L[a[i]]) {//若该节点有左子树 
83             for(int j=i+1; ; j++) {//往下 
84                 if(a[j]<=L[a[i]]) break;
85                 mp[j][temp]='|';
86             }
87         }
88     }
89     for(int i=0; i<k; i++) {//打印输出
90         for(int j=0; j<pos[a[i]]; j++)
91             cout<<mp[i][j];
92         cout<<a[i];
93         if(L[a[i]] || R[a[i]]) cout<<"-|";
94         cout<<endl;
95     }
96     return 0;
97 }
原文地址:https://www.cnblogs.com/wwqzbl/p/13578271.html