zoukankan      html  css  js  c++  java
  • 试题 历届试题 横向打印二叉树

    资源限制
    时间限制: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 }
  • 相关阅读:
    .net实现支付宝在线支付
    彻头彻尾理解单例模式与多线程
    Linq中的Select与Select many
    MVC中子页面如何引用模板页中的jquery脚本
    浅谈MemCahe
    左连接,右连接,内连接(left join ,right join,inner join)
    协变与逆变
    子类对父类中的属性和字段的改写
    里氏转换
    MVC基础篇—控制器与视图数据的传递
  • 原文地址:https://www.cnblogs.com/wwqzbl/p/13578271.html
Copyright © 2011-2022 走看看