【问题标题】:Java Triangular kind of histogramJava 三角型直方图
【发布时间】:2017-04-05 11:06:57
【问题描述】:

我在一个项目上需要一些帮助,我想创建一个 java 程序来创建一种三角形的直方图,它很难解释所以看下面的例子

input : 3 1 12 0 7
output:

                           _
                          /|\
                         / | \
                        /  |  \
                       /   |   \
                      /    |    \                   _
                     /     |     \                 /|\
                    /      |      \               / | \
                   /       |       \             /  |  \
    _             /        |        \           /   |   \
   /|\           /         |         \         /    |    \
  / | \    _    /          |          \       /     |     \
 /  |  \  /|\  /           |           \  _  /      |      \
<=======><===><=========================><=><===============>
 |     |  | |  |                       |  |  |             |

在我的代码中,我设法创建了输入部分和基础的生成器,但是三角形/piramides 生成器没有生成正确的空间,有人可以帮助我吗? 这是我制作三角形的代码(假设输入是数组 numbersnumbers2 中的内容):

public class Spires{
    public static void main(String[] args){
    int[] numbers = {3,1,12,0,7};
    int counter = 6, max = 12;
    int[] numbers2 = {3,1,12,0,7};

        for(int row = max+1; row >= 0; --row) {
            System.out.println();
            for(int col = 0; col < counter-1; ++col) {
                if(numbers2[col] >= row){
                        for(int spacesleft = 1; spacesleft < (numbers2[col] + col)+row-1; ++spacesleft){
                            System.out.print(" ");
                        }
                    if(numbers2[col] != row){
                        System.out.print("/");
                        for(int c3 = 0; c3 < numbers2[col]-row-1; ++c3) {
                            System.out.print(" ");
                        }
                        System.out.print("|");
                        for(int c3 = 0; c3 < numbers2[col]-row-1; ++c3) {
                            System.out.print(" ");
                        }
                        System.out.print("\\");

                    }else{
                        System.out.print("_");
                    }
                    // for(int spacesright = 1; spacesright <  numbers2[col] + col + row -1; ++spacesright){
                        // System.out.print(" ");
                    // }                    
                }
            }
        }
        System.out.println();
                        //base generator
        for(int i = 0; i<counter-1; ++i) {
            System.out.print("<");
            for(int i2 = 0; i2 < 2*numbers[i]+1; ++i2)  {
                System.out.print("=");
            }
            System.out.print(">");
        }       
        System.out.println();

        for(int i = 0; i<counter-1; ++i) {
            if(numbers[i] != 0){
                System.out.print(" |");
                for(int i2 = 0; i2 < 2*numbers[i]-1; ++i2)  {
                    System.out.print(" ");
                }
                System.out.print("| ");
            }else{
                System.out.print(" | ");
            }
        }
    }
}

我的输出是这样的:

                        _
                       /|\
                      / | \
                     /  |  \
                    /   |   \
                   /    |    \                _
                  /     |     \               /|\
                 /      |      \              / | \
                /       |       \             /  |  \
    _               /        |        \            /   |   \
   /|\              /         |         \           /    |    \
  / | \ _             /          |          \          /     |     \
 /  |  \/|\            /           |           \ _         /      |      \
<=======><===><=========================><=><===============>
 |     |  | |  |                       |  |  |             |

我需要一些帮助来弄清楚如何添加缺失的空格并删除一些

【问题讨论】:

  • 我会使用 StringBuilder 和 List of Strings 从下往上构建直方图。创建直方图后,我会以相反的顺序打印列表。我对您的建议是将您的单体代码分解为方法。为底线、最后一条线和三角形线创建一个方法。既然你说你的问题是三角形线的间距,那么你要调试的代码就会少很多。

标签: java histogram


【解决方案1】:

你快到了!只需进行一些调整即可。

  1. 三角腿左右两边外边空间的计算其实很简单:row + 1。因为每个三角形都是自下而上构建的,所以第 0 行(底行)显示的三角形需要 1 个空格,第 1 行需要 2 个空格,以此类推。
  2. 如果当前row 在您正在显示的三角形列的“上方”,您仍然需要输出空格来标记该三角形的占位符。所以if (numbers2[col] &gt;= row) 需要一个对应的else 来代替显示空格。

应用这两个更改会得到如下结果:

 if(numbers2[col] >= row){

    //            corrected calculation \-------/
    for(int spacesleft = 0; spacesleft < row + 1; ++spacesleft){
        System.out.print(" ");
    }

     if(numbers2[col] != row){
         System.out.print("/");
         for(int c3 = 0; c3 < numbers2[col] - row - 1; ++c3) {
             System.out.print(" ");
         }
         System.out.print("|");
         for(int c3 = 0; c3 < numbers2[col] - row - 1; ++c3) {
             System.out.print(" ");
         }
         System.out.print("\\");

     }else{
         System.out.print("_");
     }

     //              corrected calculation \-------/
     for(int spacesright = 0; spacesright < row + 1; ++spacesright){
         System.out.print(" ");
     }

 // output spaces to fill area for that column and shift everything over properly
 } else {
    for (int spaces = 0; spaces < numbers2[col] * 2 + 3; spaces++)
        System.out.print(" ");
 }

这应该会按预期输出直方图。


现在我希望您考虑一下为什么使用此代码具有挑战性。这与您必须同时记住的变量和想法的数量以及阅读和理解一段代码的难度有直接关系。

使代码更易于推理的一种方法是将其分解为不同的函数,分别处理问题的不同方面。例如,我们可能会添加以下方法:

  1. 打印一定数量的空格
  2. 打印一行三角形

此外,它还有助于使用更多具有直观名称的变量,因此您不必在整个计算过程中不断推理。这是一个应该演示的示例:

// output 'count' spaces
public static void printSpaces(int count) {
    for (int spaces = 0; spaces < count; spaces++) System.out.print(" ");
}

// output one row of a triangle based on supplied height
// and current display row, starting at 0=top row.
public static void printTriangleSection(int triangleHeight, int rowOfTriangle) {

    int triangleWidth = triangleHeight * 2 + 3; // total width taken up by this triangle
    int halfWidth = triangleHeight + 1;     // total width taken up by one side (excluding the middle)

    int spacesOutside = halfWidth - rowOfTriangle;  // total spaces outside of triangle hypotenuse
    int spacesInside = rowOfTriangle - 1;           // total spaces inside triangle hypotenuse

    if (rowOfTriangle < 0) {        // above the first row of the triangle
        printSpaces(triangleWidth);
    } else if (rowOfTriangle == 0) {
        printSpaces(spacesOutside);
        System.out.print("_");
        printSpaces(spacesOutside);
    } else {
        printSpaces(spacesOutside);
        System.out.print("/");
        printSpaces(spacesInside);
        System.out.print("|");
        printSpaces(spacesInside);
        System.out.print("\\");
        printSpaces(spacesOutside);
    }
}

那么main 方法的相关部分将简化为:

for(int row = max+1; row >= 0; --row) {
   System.out.println();
   for(int col = 0; col < counter-1; ++col) {
       printTriangleSection(numbers2[col], numbers2[col] - row);
   }
}

【讨论】:

    【解决方案2】:

    简介

    我提供这个答案的原因是写关于如何通过编码问题进行推理。三角形直方图很有趣,让我想出了一个解决方案。

    这是一个测试运行:

    Enter the heights of the triangles: 3 1 12 0 7
    
                               -                                 
                              /|\                                
                             / | \                               
                            /  |  \                              
                           /   |   \                             
                          /    |    \                   -        
                         /     |     \                 /|\       
                        /      |      \               / | \      
                       /       |       \             /  |  \     
        -             /        |        \           /   |   \    
       /|\           /         |         \         /    |    \   
      / | \    -    /          |          \       /     |     \  
     /  |  \  /|\  /           |           \  -  /      |      \ 
    <=======><===><=========================><=><===============>
     |     |  | |  |                       |  |  |             | 
    
    Enter the heights of the triangles: 
    

    推理

    输入三角形的高度,输出直方图三角形。在不输入任何数字的情况下按 Enter 键让程序知道退出。

    当我查看直方图时,我注意到了 3 件事。

    1. 我可以创建一个 Java 类来形成三角形,并为我需要绘制的每个三角形创建一个该类的实例。在示例测试运行中,我创建了 5 个三角形,因此我创建了该类的 5 个实例。

    2. 如果我先创建基行,我可以使用 符号的定位来计算三角形边的开始位置。

    3. 从下向上创建直方图比从上向下创建要容易得多。

    现在,我知道我可以使用 StringBuilder 创建一个空白字符串并使用 setCharAt 方法在空白字符串中放置字符,这对我很有帮助。这样,我就不必计算三角形之间和中间的空白数。

    我知道我可以使用 List 来存储输出字符串,并以创建它们的相反顺序打印它们,这也很有帮助。

    所以,这是我可以给你解决编码问题的第一个提示。

    如果某事看起来很难完成,请询问某人是否有更简单的方法。

    可能没有更简单的方法。有些编码问题就是这么难。但有时,您可能不知道更简单的解决方案。

    所以,这是生成直方图的代码。

    package com.ggl.testing;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    
    public class TriangleHistogram implements Runnable {
    
        public static void main(String[] args) {
            new TriangleHistogram().run();
        }
    
        @Override
        public void run() {
            Scanner scanner = new Scanner(System.in);
            List<TriangleModel> triangleHistogram = readInput(scanner);
    
            while (triangleHistogram.size() > 0) {
                String baseString = createBaseString(triangleHistogram);
                String bottomString = createBottomString(triangleHistogram,
                        baseString.length());
    
                List<String> histogramStrings = new ArrayList<>();
                histogramStrings.add(bottomString);
                histogramStrings.add(baseString);
                createTriangleStrings(triangleHistogram, histogramStrings);
    
                displayHistogram(histogramStrings);
    
                triangleHistogram = readInput(scanner);
            }
    
            scanner.close();
        }
    
        private List<TriangleModel> readInput(Scanner scanner) {
            List<TriangleModel> triangleHistogram = new ArrayList<>();
            System.out.print("Enter the heights of the triangles: ");
            String inputLine = scanner.nextLine();
    
            if (!inputLine.trim().isEmpty()) {
                String[] triangleSizes = inputLine.split("\\s");
                for (int i = 0; i < triangleSizes.length; i++) {
                    TriangleModel triangleModel = new TriangleModel(
                            Integer.parseInt(triangleSizes[i]));
                    triangleHistogram.add(triangleModel);
                }
            }
    
            return triangleHistogram;
        }
    
        private String createBaseString(List<TriangleModel> triangleHistogram) {
            StringBuilder builder = new StringBuilder();
    
            for (TriangleModel triangleModel : triangleHistogram) {
                triangleModel.setColumns(builder);
                triangleModel.createBase(builder);
            }
    
            return builder.toString();
        }
    
        private String createBottomString(List<TriangleModel> triangleHistogram,
                int length) {
            StringBuilder builder = createStringBuilder(' ', length);
    
            for (TriangleModel triangleModel : triangleHistogram) {
                triangleModel.createBottom(builder);
            }
    
            return builder.toString();
        }
    
        private void createTriangleStrings(List<TriangleModel> triangleHistogram,
                List<String> histogramStrings) {
            String histogramString = "";
    
            do {
                String baseString = histogramStrings.get(1);
                StringBuilder builder = createStringBuilder(' ',
                        baseString.length());
    
                for (TriangleModel triangleModel : triangleHistogram) {
                    triangleModel.createTriangle(builder);
                }
    
                histogramString = builder.toString();
                histogramStrings.add(histogramString);
            } while (!histogramString.trim().isEmpty());
    
        }
    
        private StringBuilder createStringBuilder(char c, int length) {
            StringBuilder builder = new StringBuilder(length);
    
            for (int i = 0; i < length; i++) {
                builder.append(c);
            }
    
            return builder;
        }
    
        private void displayHistogram(List<String> histogramStrings) {
            for (int i = histogramStrings.size() - 1; i >= 0; i--) {
                String line = histogramStrings.get(i);
                System.out.println(line);
            }
    
            System.out.println();
        }
    
        public class TriangleModel {
            private final int height;
    
            private int leftColumn;
            private int centerColumn;
            private int rightColumn;
    
            public TriangleModel(int height) {
                this.height = height;
            }
    
            public void setColumns(StringBuilder builder) {
                this.leftColumn = builder.length() + 1;
                this.centerColumn = leftColumn + height;
                this.rightColumn = centerColumn + height;
            }
    
            public void createBase(StringBuilder builder) {
                builder.append('<');
                for (int i = 0; i < getBaseWidth(); i++) {
                    builder.append('=');
                }
                builder.append('>');
            }
    
            public void createBottom(StringBuilder builder) {
                builder.setCharAt(leftColumn, '|');
                builder.setCharAt(rightColumn, '|');
            }
    
            public void createTriangle(StringBuilder builder) {
                if (leftColumn < rightColumn) {
                    builder.setCharAt(leftColumn, '/');
                    builder.setCharAt(centerColumn, '|');
                    builder.setCharAt(rightColumn, '\\');
    
                    leftColumn++;
                    rightColumn--;
                } else if (leftColumn == rightColumn) {
                    builder.setCharAt(centerColumn, '-');
    
                    leftColumn++;
                    rightColumn--;
                }
            }
    
            private int getBaseWidth() {
                return height + height + 1;
            }
    
        }
    
    }
    

    说明

    我使主 TrigleHistogram 类实现 Runnable,以便我可以将主代码放在 run 方法中。我不喜欢在类的构造函数中放很多代码。

    run 方法是代码中发生的事情的概要。我从用户那里得到高度,然后创建直方图。我先创建基线,然后是底线,然后是倒序的三角形。

    run 方法中的 while 循环使用启动读取。我在 while 循环之前调用 readInput 方法一次,在 while 循环结束时再调用一次。这样,当用户只需按下 Enter 键时,我就不必跳过 while 循环的任何部分。

    readInput 方法不做任何错误检查。可以在 readInput 方法中添加错误检查。

    我将 TriangleHistogram 类中的代码分解为多个方法。每个方法都按照方法名称执行的操作。命名方法对于描述性进行很重要。通常,我使用动词-名词结构。

    TriangleModel 类绘制一个三角形。在课堂上看,没有多少数学涉及。在创建基线时,我设置了左侧中心的列和三角形的右侧部分。在创建直方图的每一行时,我会调整左右列,直到它们在三角形顶部相遇。

    您可以在 TriangleModel 方法中看到,将字符放在空白 StringBuilder 上比附加空白和字符要简单得多。

    发展

    我没有一口气写完整个程序。我编写了程序的一小部分并对其进行了测试。写一点,测试一点的好处是,当你发现问题时,你可以很好地知道问题出在哪里。

    1. 我编写了 readInput 方法和足够的 run 方法来练习 while 循环。我写了足够多的 TriangleModel 类来保持高度。该程序除了处理输入、创建一个 TriangleModel 对象列表之外没有做任何事情,并且没有崩溃。不崩溃的部分是最重要的。

    2. 我将其余字段添加到 TriangleModel 类并创建了直方图的基线。最后,我可以看看一些输出!耶!

    3. 我创建了直方图的底线。这让我可以验证三角形的左列和右列是否定义正确。

    4. 我在直方图底部上方创建了一条线。这使我能够验证三角形的中心列是否正确定义,并且输出字符串列表已创建并以相反的顺序打印。

    5. 我编写了其余的代码。这是我的程序首先崩溃的地方。当它们相等时,我忘记调整左右列。我很快就发现了问题,因为我知道问题出在新代码中。

    然后我就完成了。我花了一些时间清理了一些代码,并使字段名称和方法名称更具描述性。

    您可以学习这些编写代码的技巧。这是我能给你的最后一个提示。

    您不是在为编译器编写代码。您正在编写代码,以便其他人(包括 3 个月后的您自己)能够阅读并轻松理解代码。

    从宽泛的想法开始,随着代码的进一步深入,深入了解更多细节。

    我希望这个答案会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多