2009-12-31 61 views
6

我决定递归地实现一个非常简单的程序,以查看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); 
    } 
} 

而且工作正常,但因为它有点难看,我想知道是否有更好的方法。如果任何人有任何想法/替代品/语法糖分享,这将非常感激!

P.s.如果你说“使用Lisp”,你就赢不了什么(但是尊重)。我想知道这是否可以在Java中看起来不错。

*以及效果如何手柄递归

+0

递归是不是要在Java作为迭代除了极少数情况下简单或有效的。 – 2009-12-31 13:06:04

+0

是的,但是如果任何人都将为递归的空间复杂性做好充分的准备,那么这是一个Java开发人员:) – 2009-12-31 13:35:39

+2

在任何语言中,您总是必须复制数组或将索引传递到该数组。如果你的意思是“Lisp使用链表”,那么当然,它比“使用数组的Java”更好,但我认为“使用链表的X”比任何X和Y的“Y使用数组”更好。 Common Lisp中的位移数组为您处理一些簿记,但我认为他们确实不会让这种情况变得更简单。) – Ken 2010-01-01 03:49:29

回答

7

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)开始递归。

+0

我其实更喜欢这个,因为它的递归使用比获胜的答案更加有效,但它并没有做一些胜利者的事情。谢谢虽然:) – 2010-01-08 14:28:50

+0

如?唯一的区别是我处理的是一个空数组,它在这里抛出一个异常(好,没有最大,所以没有很好的答案),而在胜出的答案中返回任意(假)值。 – Jerome 2010-01-08 15:15:34

+0

好点。改变。 – 2012-04-25 15:51:40

2

你可以通过当前指数作为参数,而不是每次都几乎复制整个数组或者你可以使用分而治之的办法。

10

以下是我可能使递归方法看起来更漂亮:

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); 
    } 
+1

JOOI,Math.max和三元运算符之间有什么区别吗? – 2009-12-31 10:27:14

+0

是的,我发现使用'max()'比使用Java条件运算符出于同样的目的更容易阅读。如果性能存在差异,则必须针对您的特定环境进行测量。 – 2009-12-31 10:49:07

+1

用max()你不必重复自己。 – Ken 2010-01-01 03:44:02

1
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; 
} 
0

您的递归代码使用System.arrayCopy,但您的迭代代码不会执行此操作,因此您的microbenchmark不会准确。正如其他人所提到的,您可以使用Math.min并使用数组索引而不是类似队列的方法来清理该代码。

1

...去看看的Java如何处理递归

简单的答案是,Java不处理递归很好。具体而言,Sun Java编译器和Hotspot JVM不实现尾调用递归优化,因此递归密集型算法可以轻松消耗大量堆栈空间。

但是,我看到有文章说IBM的JVMs 支持这种优化。我看到一些非Sun人的电子邮件,他说他将它作为一个实验性的Hotspot扩展程序添加为论文项目。

+0

我想知道这是否有什么结果。 – 2014-11-26 06:57:07

+0

[显然没有](http://www.drdobbs.com/jvm/tail-call-optimization-and-java/240167044):) – 2014-11-26 07:00:35

1

这里的展示链表怎么常常是递归的,这里的“更好”是指“在方法签名参数少”

private static int recursive(LinkedList<Integer> list) { 
    if (list.size() == 1){ 
     return list.removeFirst(); 
    } 
    return Math.max(list.removeFirst(),recursive(list)); 
    } 
0
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); 
    } 
} 
+1

欢迎来到堆栈溢出!你会考虑增加一些叙述来解释为什么这段代码有效吗?是什么使它成为这个问题的答案?这对询问问题的人以及任何其他人来说非常有帮助。 – 2013-02-19 21:01:12

0

其实我有一个预发类更好一点一定的变化,我设置为找到任何一组值的最大整数。你可以把这个类到你的项目,只是使用它在任何类,像这样:

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; 
    } 
} 
0

以下是他的一次演讲中通过我的Java讲师,宾夕法尼亚吴教授,给出一个示例代码。希望能帮助到你。

 
import java.util.Random;

public class Recursion
{
static int s = 0;

public static Double max(Double[] d, int n, Double max)
{
if (n==0) { return max;}
else
{

if (d[n] > max)
{
max = d[n];
}

return max(d, n-1, max);

}
}

public static void main(String[] args)
{
Random rn = new Random();
Double[] d = new Double[15];

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

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

欢迎来到SO!请考虑编辑您的问题,以包含有关此代码为何以及如何回答问题的详细说明。此外,您可能希望在发布教授代码或与上述代码相关的姓名之前获得许可,这只是一种常见礼节。 – filoxo 2015-09-13 02:51:14

0

这里是我的替代

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)); 
    } 
}