【问题标题】:How to print an array of objects using recursion?如何使用递归打印对象数组?
【发布时间】:2018-04-20 13:19:38
【问题描述】:

我将创建一个 Book 类的数组,我不相信 Book 类的内容,但我已经实现了 Comparable,尽管在这个确切的示例中并不需要使用它。我需要返回一个字符串。在过去的示例中,我们总是这样做,以便它是无效的,但使用 System.out.println。我对整个递归的掌握程度很低,所以如果有人可以提供帮助,我将不胜感激。谢谢

【问题讨论】:

  • 这对于学习基本递归来说似乎相当复杂。首先熟悉使用递归简单地输出一些数字序列(例如1 2 3 ... 10)。然后想想这个任务
  • @Fureeish 我知道该怎么做,但是我看到的每个示例都没有以 String 类型输出它,而是始终使用 void 所以我不确定如何编写输出
  • 在这种情况下,我建议您考虑一种递归方法,该方法将总结第一个n 数字。提示:如果方法签名是int sum(int n),那么该方法内的代码部分将是return n + sum(n - 1);。小心 - 再次阅读结束条件。学习基本递归通常会导致无限“循环”或方法调用

标签: java arrays recursion


【解决方案1】:

递归不是解决这个问题的正确策略。听起来您正在寻求家庭作业帮助,因此我建议您让您的助教或学校的其他资源参与进来,以更好地了解您的问题的背景。既然你提到它:实现Comparable 不是打印数组所必需的。如果您打算对数组进行排序,则需要Comparable

也就是说,这听起来像是您需要的组件:

  1. 您的Book 类需要一个字符串表示。在 Java 中,通常您将其编码为 toString 方法:

    class Book
    {
       private String title;
    
       // ...other Book methods defined here...
    
       public String toString()
       {
           return this.title; // Or whatever the correct string representation of your Book is.
       }
    }
    
  2. 我假设你已经初始化了一个 Books 数组,比如在你的 main 函数中。通常,您会迭代地打印列表。这要简单得多。看到这个答案:How to print out individual Strings from Iterable<String>

    但是,您的问题是特定于递归的。递归函数总是需要两个元素:

    1. 基本案例
    2. 递归步骤

    递归迭代列表在函数式编程中很常见,常见的基本情况是空列表。 Java 数组不适合这种模式,尽管像LinkedList 这样的一些List 实现是。也就是说,我们可以通过使递归步骤增加一个计数器来使用数组。与在for 循环中迭代列表相比,这实际上具有零优势,并且具有容易发生堆栈溢出的主要缺点。但是,你要求递归......

    public String stringifyBooks(Book[] books, int currentIndex)
    {
         // From https://stackoverflow.com/questions/47169798/how-to-print-an-array-of-objects-using-recursion
         if (currentIndex >= books.length || currentIndex < 0)
         {
             // Base case
             return "";
         }
         else
         {
             // Recursive step
             return books[currentIndex].toString() + ", " +
                 stringifyBooks(books, currentIndex + 1);
         }
    }
    

    现在您可以使用Books 数组和初始索引调用stringifyBooks,您将获得从该索引开始的所有书籍字符串。如果传递的初始索引大于书籍数组的长度,或者书籍是空数组,会发生什么情况?

    当您自己尝试时,您可能会注意到此解决方案会产生一个尾随 ", "。为避免这种情况,您可以尝试 (a) 调整基本情况(或添加第二个“基本情况”),或者您可以 (b) 调整递归步骤以识别递归函数调用何时遇到基本情况(提示: 检查基本情况返回的值并在递归步骤中考虑)。

    使用递归会受到 Java 堆栈大小限制的影响。在一大堆书(比如 10,000 本书)上试一试,你可能会遇到限制。此外,所有字符串连接的成本将非常大。顺便说一句,如果您在迭代算法(即使用for 循环的算法)中累积字符串,您也将支付这笔费用。由于这个原因,Java 提供了一个内置的StringBuilder。看看您是否可以修改上面的代码以在递归步骤中将每本书接收到 StringBuilderappend,而不是在每个递归步骤中使用 + 运算符连接字符串。 (请注意,此修改将意味着 stringifyBooks 将返回 void 而不是 String - 您的 StringBuilder 参数最终实际上是您的返回值。)

    最后,如果您打算使用List&lt;Book&gt; 而不是Book[],您可以构造一个递归函数,其中:(1) 基本情况检查ListisEmpty 函数并返回"" ; (2)递归案例创建列表中第一个元素的字符串,移除第一个元素,调用列表上的递归函数,然后返回第一个元素的字符串+递归函数调用的结果。 (或者用StringBuilder 做同样的事情。)如果你这样做,你会删除currentIndex 变量。请记住,这会破坏您的书籍列表,因此如果您在使用该函数后需要它,则需要在调用递归函数之前克隆它。

【讨论】:

    【解决方案2】:

    要从方法中返回字符串,您只需在方法头中这样说:

    public String getName(){
        return this.name;
    }
    

    如果您想返回 Object 的 String 表示,约定是使用 .toString() 方法。 String.format() 对此非常有帮助。

    public String toString(){
        return String.format("Name: %s Number of pages: %d", this.name, this.numPages);
    }
    

    编辑:

    使用递归打印这些对象的数组:

    public static String arrayAsString(Book[] books, int startIndex){
        if(startIndex > books.length - 1) return null;
    
        String toAppend = arrayAsString(books, startIndex + 1);
    
        if(toAppend == null) return books[startIndex].toString();
        else return books[startIndex].toString() + " " + toAppend;
    }
    

    【讨论】:

    • 这如何触及“使用递归”部分..?
    • 你不需要递归来返回一个字符串,这是 OP 提出的问题,除非我遗漏了什么或者他/她在原始问题中遗漏了一些东西。
    • 字面意思将“using recursion”部分放在title中...他还提到了一个数组用户自定义对象
    • 哈哈抱歉,我修正了我的答案。
    猜你喜欢
    • 2021-12-10
    • 2011-09-05
    • 2020-03-17
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    • 1970-01-01
    • 1970-01-01
    • 2012-05-01
    相关资源
    最近更新 更多