【问题标题】:How would one go about "chopping up" an array using recursion?如何使用递归“分割”一个数组?
【发布时间】:2019-09-15 19:10:27
【问题描述】:

如何在 Java 中使用递归从主数组中创建新的、更小的数组?我能想到的唯一方法就是返回一个数组,否则会超出范围。

我来这里的目的是寻找证据来证明通过数组递归与循环一样有效,因为方法中定义的数组和本地数组都指向内存中的相同位置。

但是我遇到了这个答案:https://stackoverflow.com/a/5112821/10807670,它指出您应该使用原始数组,而不是“切碎”的版本,这意味着这种事情可能会偶然发生。

我设法证明主数组和方法中定义的数组是同一个数组,但我仍然不确定如何使用递归从原始数组中创建多个子数组。

class Main {
  public static void main(String[] args) {
    int[] list={2,4,6,8,10};
    System.out.println(list[0]);
    System.out.println(list[1]);
    change(list, 0);
    System.out.println(list[0]);
    System.out.println(list[1]);
  }

  public static void change(int[] list1, int index){
      //does a recursive call initialize a new array or does it point to the same array in memory?

    list1[index]=1; //set all indices to 1

    if (index==list1.length-1) return;

    else change(list1, index+1);
    return;
    }
}

原始响应奇怪地让我认为每次增加索引时,都会使用一个较小的数组调用 change 方法,该数组之后开始一个索引,我猜这是真的,但只是在概念上,因为这些索引仍然存在,只是没有被访问。

相反,当我更改数组 list1 时,它也会更改数组列表,正如我所料,因为它们是同一个数组。有没有办法像原帖暗示的那样“切碎”,比如说,制作一系列新数组,如 {4,6,8,10}、{6,8,10}、{8,10}等?

【问题讨论】:

    标签: java arrays recursion sublist


    【解决方案1】:

    递归处理数组可以以不同的形式实现。为了实用起见,我将比较两种常用的内存使用方式。

    假设我们想要找到数组元素的总和。让我们考虑两种方式:

    • 在每个递归步骤中 - 将下一个索引传递给进程:
    int sum(int[] nums) {
      return sum(0, nums);
    }
    
    int sum(int index, int[] nums) {
      if (index == nums.length) {
        return 0;
      } else {
        return nums[index] + sum(index + 1, nums);
      }
    }
    
    • 在每个递归步骤中 - 将新数组传递给进程:
    int sum(int[] nums) {
      if (nums.length == 0) {
        return 0;
      } else {
        return nums[0] + sum(Arrays.copyOfRange(nums, 1, nums.length));
      }
    }
    

    这两种方法都会找到数组元素的总和。但它会带来不同的成本:

    • 第一种方法将使用O(n) 额外的内存,因为在每个递归步骤中,它只需要分配常量O(1) 的内存量,并且总共有n 步骤

    • 第二种方法将使用O(n^2) 额外的内存,因为在每个递归步骤中,它需要分配O(n) 额外的内存(当创建原始数组的副本时)并且总体上有n 步骤

    在实践中,您会发现不同的变化,老实说,哪种方法最好,实际上取决于手头的任务。

    【讨论】:

      【解决方案2】:

      要以递归方法创建新的子列表,请创建数组范围的副本。看看https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#copyOfRange(int[],%20int,%20int)

      【讨论】:

        【解决方案3】:

        java 中所有非原始值的传递都是通过引用完成的,因此它与递归调用中的数组相同,正如您已经证明的那样。但是循环仍然更有效,因为调用函数需要额外的操作(例如,复制函数的参数)。循环不需要这些动作,所以我想说它在效率方面仍然获胜。下面解释了在 Java 中调用方法时会发生什么:What happens after a method is called in Java

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-12-28
          • 1970-01-01
          • 2013-03-09
          • 2020-10-30
          • 2010-11-11
          • 2020-06-28
          • 1970-01-01
          相关资源
          最近更新 更多