【问题标题】:Java recursive functionsJava 递归函数
【发布时间】:2018-01-02 16:33:18
【问题描述】:

我还不太了解递归,并且有一些我无法解决的作业。有人有想法吗?

任务 1: 实现一个 int 方法 max(int[]arr, int i),它返回 arr 所有元素的最大值,索引

到目前为止,这是我的代码:

private static int max = 0;

private static int max(int[] arr, int i) {
    if (i >= 0 && i < arr.length) {
        if (arr[i] >= max) {
            max = arr[i];
        }

        max(arr, i - 1);
    }
    return max;
}

实际上它可以工作,但它的风格很糟糕,所以我的问题是:如何在没有私有静态 int max 的情况下实现递归方法?我不允许在方法中添加第三个参数。

任务 2: 实现一个布尔方法 containsValue(int[] arr, int val) 如果 arr 的元素之一匹配 val,则返回 true。该方法应该有两个递归调用:一个搜索数组的前半部分,一个搜索后半部分。您可以使用 Arrays.copyOfRange(...)。

这是我的代码:

private static boolean containsValue(int[] arr, int val) {
    if (arr.length > 1) {
        if (arr[arr.length - 1] == val) {
            return true;
        }
        return containsValue(Arrays.copyOfRange(arr, 0, arr.length-1), val);
    }

    return false;
}

这也有效,我明白为什么,但显然该方法没有两个递归调用。每次尝试实现将数组分成两半的方法都是一个巨大的失败。谁能帮帮我?

【问题讨论】:

  • @nafas 不,这些是关于递归的具体问题。递归可能不是解决这个问题的最佳方法,而 OP 尤其需要它来做作业。此处不要求进行一般性审查,但它清楚地表明了研究、努力和少量理解。 OP 只是想要一种特定的、不同的实现方法。我敢说它已经是一个 MCVE,为什么不适合 Stack Overflow?
  • 对于第一个,考虑将当前值与递归调用返回的值进行比较。这样你就可以消除静态变量了。
  • @Mast ** 在我看来 **(是的,我们根据自己的意见投票),家庭作业会让学生失败,只有失败才能让我们成为最好的。代码审查会显示你做错了什么,而新的解决方案只会为家庭作业提供更好的答案。在这种情况下,一个人将获得满分,并且永远不会费心去找出原因!!!!
  • @nafas 这就是教育。评论不会改变这一点。

标签: java arrays recursion boolean


【解决方案1】:

对于一般的递归,您需要以下结构:

if the problem is simple enough to answer easily:
   return the answer
else:
   split the problem into two parts
   recurse to get the answer
   return the answer

对于max(),这是:

if the input list is of size 1:
   return the only element of the list
else
   split the list into a head (first element) and a tail (rest of the list)
   recurse to get the max of tail
   return the head or the max of tail, whichever is largest

或者在 Java 中:

int max(int[] list) {
   if(list.length == 1) {
        return list[0];
   } else {
        return Math.max(list[0], max(tail(list)));
   }
}

(您需要自己实现int[] tail(int[] list),使用Arrays.copyOfRange()

此实现不处理长度为零的输入列表——这将是一个无意义的调用,具有未定义的结果。如果你愿意,你可以让它抛出一个信息更丰富的异常。


你的第二个作业基本上可以用相同的方式编写,除了现在有两个“简单”的情况我们不递归:

  • 如果输入列表为空,则答案为false
  • 如果输入列表的第一个元素是我们正在寻找的,答案是true
  • 否则不“容易”,所以递归。

所以:

boolean contains(int value, int[] list) {
   if(list.length == 0) {
        return false;
   } 

   if(list[0] == value) {
      return true;
   }

   return contains(value, tail(list));
}

... 除了你被告知要递归到数组的前半部分,然后是后半部分。所以,就照你说的做吧:

int contains(int value, int[] list) {
   if(list.length == 0) {
      return false;
   }

   if(list.length == 1) {
       return list[0] == value;
   }

   return contains(value, firstHalf(list)) || 
          contains(value, secondHalf(list));
}

您需要编写自己的firstHalf()secondHalf() 实现,再次使用Arrays.copyOfRange()。确保当输入列表为奇数长度时,中间值仅在其中一半中。


注意这是如何声明性 - 它几乎直接翻译成英文陈述:“我知道如果列表为空,它就不存在。如果它是列表的第一个元素,它就存在,或者如果列表的尾部包含它。”


请注意,在这两种情况下,递归都不是在 Java 中实现此功能的有效方法。但我相信你的老师会指导你更实际和必要的递归应用。

【讨论】:

  • 老师将第一种方法的签名指定为int max(int[]arr, int i),其中i是要检查的最大索引。因此,您可以将方法简化为:ideone.com/IN5aPR
  • 我可以,但你也可以——在这种情况下你不需要使用copyOfRange()——你可以每次都传递同一个数组。 if(list.length == 1) 变为 if(i = list.length -1)(即“我们在最后一项”),而不是每次都检查 list[0],而是检查 list[i]。并使用i + 1 进行递归。
猜你喜欢
  • 2015-07-13
  • 1970-01-01
  • 2012-10-26
  • 1970-01-01
  • 2020-07-15
  • 2012-09-19
  • 2015-03-01
  • 2018-08-07
相关资源
最近更新 更多