【问题标题】:Finding the largest positive int in an array by recursion通过递归找到数组中最大的正整数
【发布时间】:2010-12-31 09:09:11
【问题描述】:

我决定递归实现一个非常简单的程序,看看 Java 处理递归的能力如何*,结果有点短。这就是我最终写的:

public class largestInIntArray {
  public static void main(String[] args)
  {
    // These three lines just set up an array of ints:
    int[] ints = new int[100];
    java.util.Random r = new java.util.Random();
    for(int i = 0; i < 100; i++) ints[i] = r.nextInt();

    System.out.print("Normal:"+normal(ints,-1)+" Recursive:"+recursive(ints,-1));
  }

  private static int normal(int[] input, int largest) {
    for(int i : input)
      if(i > largest) largest = i;

    return largest;
  }

  private static int recursive(int[] ints, int largest) {
    if(ints.length == 1)
      return ints[0] > largest ? ints[0] : largest;

    int[] newints = new int[ints.length - 1];
    System.arraycopy(ints, 1, newints, 0, ints.length - 1); 

    return recursive(newints, ints[0] > largest ? ints[0] : largest);
  }
}

这很好用,但由于它有点难看,我想知道是否有更好的方法。如果有人有任何想法/替代方案/语法糖要分享,将不胜感激!

附:如果您说“使用 Lisp”,您将一无所获(但尊重)。我想知道这是否可以在 Java 中看起来不错。

*以及如何处理递归

【问题讨论】:

  • 递归在 Java 中不会像迭代那样简单或高效,除非是极少数情况。
  • 是的,但如果有人要为递归的空间复杂性做好充分准备,那就是 Java 开发人员 :)
  • 在任何语言中,您总是必须复制数组或将索引传递到该数组。如果您的意思是“使用链表的 Lisp”,那么肯定比“使用数组的 Java”更好,但我认为对于任何 X 和 Y,“使用链表的 X”都比“使用数组的 Y”更好。( Common Lisp 中的置换数组会为您处理一些簿记工作,但我认为它们并没有真正让这种情况变得更简单。)

标签: java recursion puzzle


【解决方案1】:

以下是我可以使递归方法看起来更好的方法:

  private static int recursive(int[] ints, int largest, int start) {
    if (start == ints.length) {
      return largest;
    }
    return recursive(ints, Math.max(ints[start], largest), start + 1);
  }

这避免了昂贵的数组副本,并且适用于空输入数组。您可以实现一个额外的重载方法,只有两个参数与迭代函数的签名相同:

  private static int recursive(int[] ints, int largest) {
    return recursive(ints, largest, 0);
  }

【讨论】:

  • JOOI,Math.max 和大于的三元运算符有什么区别吗?
  • 是的,我发现使用max() 比使用Java 条件运算符更容易阅读。如果存在性能差异,则必须针对您的特定环境进行衡量。
  • 使用 max(),您不必重复自己。
【解决方案2】:

2 项改进:

  • 没有数组的副本(仅使用偏移量)
  • 无需给出当前最大值

    private static int recursive(int[] ints, int offset) {
        if (ints.length - 1 == offset) {
            return ints[offset];
        } else {
            return Math.max(ints[offset], recursive(ints, offset + 1));
        }
    }
    

recursive(ints, 0)开始递归。

【讨论】:

  • 我实际上更喜欢这个,因为它对递归的使用比获胜的答案更优雅,但它并没有做一些获胜者所做的事情。不过谢谢:)
  • 比如?在我看来,唯一的区别是处理一个在这里抛出异常的空数组(很好,没有最大值,所以没有好的答案)与在获胜答案中返回任意(假)值。
【解决方案3】:

您可以将当前索引作为参数传递,而不是每次都复制几乎整个数组,或者您可以使用分而治之的方法。

【讨论】:

    【解决方案4】:
    public static int max(int[] numbers) {
      int size = numbers.length;
      return max(numbers, size-1, numbers[size-1]);
    }
    
    public static int max(int[] numbers, int index, int largest) {
      largest = Math.max(largest, numbers[index]);
      return index > 0 ? max(numbers, index-1, largest) : largest;
    }
    

    【讨论】:

      【解决方案5】:

      ...看看 Java 处理递归的能力如何

      简单的答案是 Java 不能很好地处理递归。具体来说,Sun Java 编译器和 Hotspot JVM 没有实现尾调用递归优化,因此递归密集型算法很容易消耗大量堆栈空间。

      但是,我看到一些文章说 IBM 的 JVM确实支持这种优化。我看到了一封来自非 Sun 人员的电子邮件,他说他将把它作为一个实验性的热点扩展作为论文项目添加。

      【讨论】:

      【解决方案6】:

      这里有一个细微的变化,展示了链接列表在递归方面通常更好一点,其中“更好”意味着“方法签名中的参数更少”

        private static int recursive(LinkedList<Integer> list) {
          if (list.size() == 1){
            return list.removeFirst();
          }
          return Math.max(list.removeFirst(),recursive(list));
        }
      

      【讨论】:

        【解决方案7】:

        您的递归代码使用System.arrayCopy,但您的迭代代码没有这样做,因此您的微基准测试不会准确。正如其他人所提到的,您可以使用 Math.min 并使用数组索引而不是您使用的类似队列的方法来清理该代码。

        【讨论】:

          【解决方案8】:
          public class Maximum 
          {
          
              /**
               * Just adapted the iterative approach of finding maximum and formed a recursive function
               */
              public static int max(int[] arr,int n,int m)
              {
                  if(m < arr[n])
                  {
                      m = arr[n];
                      return max(arr,n - 1,m);
                  }
                  return m;
              }
              public static void main(String[] args) 
              {
                 int[] arr = {1,2,3,4,5,10,203,2,244,245,1000,55000,2223};
                 int max1 =  max(arr,arr.length-1,arr[0]);
                 System.out.println("Max: "+ max1);
              }
          }
          

          【讨论】:

          • 欢迎来到 Stack Overflow!您是否会考虑添加一些叙述来解释为什么此代码有效,以及是什么使它成为问题的答案?这对提出问题的人以及其他任何出现的人都非常有帮助。
          【解决方案9】:

          我实际上有一个预制类,我设置它来查找任何一组值中的最大整数。您可以将此类放入您的项目中,然后在任何类中简单地使用它,如下所示:

           System.out.println(figures.getLargest(8,6,12,9,120));
          

          这将返回值“120”并将其放在输出中。如果您有兴趣使用它,这里是方法源代码:

          public class figures {
          
          public static int getLargest(int...f) {
             int[] score = new int[f.length];
              int largest=0;
              for(int x=0;x<f.length;x++) {
                  for(int z=0;z<f.length;z++) {
                      if(f[x]>=f[z]) {
                          score[x]++;
                      }else if(f[x]<f[z]) {
          
                      }else {
                          continue;
                      }
                      if(z>=f.length) {
                          z=0;
                          break;
                      }
                  }
              }
              for(int fg=0;fg<f.length;fg++) {
                  if(score[fg]==f.length) {
                      largest = f[fg];
                  }
              }
              return largest;
              }
          }
          

          【讨论】:

            【解决方案10】:

            以下是我的 Java 讲师 Penn Wu 教授在他的一次讲座中给出的示例代码。希望对您有所帮助。

            导入 java.util.Random;

            公共类递归
            {
            静态 int s = 0;

            public static Double max(Double[] d, int n, Double max)
            {
            如果 (n==0) { 返回最大值;}
            否则
            {

            如果 (d[n] > 最大值)
            {
            最大值 = d[n];
            }

            返回最大值(d, n-1, max);

            }
            }

            公共静态 void main(String[] args)
            {
            随机 rn = new Random();
            双[] d = 新双[15];

            对于 (int i=0; 我 {
            d[i] = rn.nextDouble();
            System.out.println(d[i]);
            }

            System.out.print("\nMax: " + max(d, d.length-1, d[0]));
            }
            }

            【讨论】:

            • 欢迎来到 SO!请考虑编辑您的问题,以详细说明此代码为何以及如何回答问题。此外,作为一种常见的礼貌,您可能希望在发布教授的代码或与该代码相关联的姓名之前获得许可。
            【解决方案11】:

            这是我的选择

            public class recursion
            {
              public static int max( int[] n, int index )
              {
                if(index == n.length-1)   // If it's simple, solve it immediately:
                  return n[index];        // when there's only one number, return it
                if(max(n, index+1) > n [index]) // is one number bigger than n?
                  return max(n, index+1); // return the rest, which contains that bigger number
                return n[index];          // if not, return n which must be the biggest number then
              }
            
              public static void main(String[] args)
              {
                int[] n = {100, 3, 5, 1, 2, 10, 2, 15, -1, 20, -1203}; // just some numbers for testing
                System.out.println(max(n,0));
              }
            }
            

            【讨论】:

              猜你喜欢
              • 2012-10-18
              • 2023-04-07
              • 1970-01-01
              • 1970-01-01
              • 2015-12-14
              • 2021-08-10
              • 1970-01-01
              • 2019-08-08
              • 1970-01-01
              相关资源
              最近更新 更多