2016-08-22 138 views
2

我無法用Stream替換包含遞歸調用的for循環。該代碼是關於在知道該數字的主要因素時生成給定數字的適當除數。該算法取自here,它在圖像中描繪。這是一個部分我的演示目的的代碼,它是可運行:用for循環替換遞歸

public class Demo { 

    private static void generateDivisorsTraditional(int start, long lastFactor, Multiset<Long> primeFactors, Set<Long> divisors) { 
     for (int i = start; i < primeFactors.elementSet().size(); i++) { 
      long prime = Iterables.get(primeFactors.elementSet(), i); 
      int count = primeFactors.count(prime); 
      ++start; 

      for (int c = 0; c <= count; c++) { 
       long factor = ArithmeticUtils.pow(prime, c); 
       divisors.add(lastFactor * factor); 
       generateDivisorsTraditional(start, lastFactor * factor, primeFactors, divisors); 
      } 
     } 
    } 

    private static void generateDivisorsStream(int start, long lastFactor, Multiset<Long> primeFactors, Set<Long> divisors) { 
     IntStream.range(start, primeFactors.elementSet().size()) 
       .forEach((int i) -> { 
        long prime = Iterables.get(primeFactors.elementSet(), i); 
        int count = primeFactors.count(prime); 
        final int begin = start + 1; 

        IntStream.range(0, count + 1) 
          .forEach((int c) -> { 
           long factor = ArithmeticUtils.pow(prime, c); 
           divisors.add(lastFactor * factor); 
           generateDivisorsStream(begin, lastFactor * factor, primeFactors, divisors); 
          }); 
       }); 
    } 

    private static void testTraditional(Multiset<Long> primeFactors) { 
     Set<Long> divisors = new TreeSet<>(); 
     generateDivisorsTraditional(0, 1, primeFactors, divisors); 
     System.out.println("Traditional=> " + divisors); 
    } 

    private static void testStream(Multiset<Long> primeFactors) { 
     Set<Long> divisors = new TreeSet<>(); 
     generateDivisorsStream(0, 1, primeFactors, divisors); 
     System.out.println("Stream=> " + divisors); 
    } 

    private static void testStream1(Multiset<Long> primeFactors) { 
     Set<Long> divisors = new TreeSet<>(); 
     new Inner().generateDivisorsStream(1, primeFactors, divisors); 
     System.out.println("Stream1=> " + divisors); 
    } 

    public static void main(String[] args) { 
     System.out.println("Test number: 10"); 
     Multiset<Long> primeFactors = TreeMultiset.create(); 
     primeFactors.add(2L); 
     primeFactors.add(5L); 

     testTraditional(primeFactors); 
     testStream(primeFactors); 
     testStream1(primeFactors); 

     System.out.println(); 

     System.out.println("Test number: 90"); 
     primeFactors = TreeMultiset.create(); 
     primeFactors.add(2L); 
     primeFactors.add(3L); 
     primeFactors.add(3L); 
     primeFactors.add(5L); 

     testTraditional(primeFactors); 
     testStream(primeFactors); 
     testStream1(primeFactors); 
    } 

    private static class Inner { 
     private int start = 0; 

     private void generateDivisorsStream(long lastFactor, Multiset<Long> primeFactors, Set<Long> divisors) { 
      IntStream.range(start, primeFactors.elementSet().size()) 
        .forEach((int i) -> { 
         long prime = Iterables.get(primeFactors.elementSet(), i); 
         int count = primeFactors.count(prime); 
         ++start; 

         IntStream.range(0, count + 1) 
           .forEach((int c) -> { 
            long factor = ArithmeticUtils.pow(prime, c); 
            divisors.add(lastFactor * factor); 
            generateDivisorsStream(lastFactor * factor, primeFactors, divisors); 
           }); 
        }); 
     } 
    } 
} 

輸出它發生是:

Test number: 10 
Traditional=> [1, 2, 5, 10] 
Stream=> [1, 2, 5, 10, 25] 
Stream1=> [1, 2, 5] 

Test number: 90 
Traditional=> [1, 2, 3, 5, 6, 9, 10, 15, 18, 30, 45, 90] 
Stream=> [1, 2, 3, 5, 6, 9, 10, 15, 18, 25, 27, 30, 45, 50, 75, 81, 90, 125, 135, 225, 405] 
Stream1=> [1, 2, 3, 5, 9] 

正如其名稱所暗示的方法generateDivisorsTraditional使用傳統的for循環和內我有一個遞歸調用相同的方法。方法generateDivisorsStream使用IntStream.range()來模擬for循環。

我懷疑++start;final int begin = start + 1;generateDivisorsTraditionalgenerateDivisorsStream分別有所不同。我也嘗試使用final int begin = start + 1;而不是++start;generateDivisorsTraditional,並且發現它已經開始產生錯誤的結果。我在內部類Inner中也有另一個變體,它也會產生錯誤的輸出。

我想知道爲什麼這不是表現它的行爲方式?我犯了什麼錯誤?

回答

1

我覺得有一些失誤:

private static void generateDivisorsTraditional(int start, long lastFactor, Multiset<Long> primeFactors, Set<Long> divisors) { 
    for (int i = start; i < primeFactors.elementSet().size(); i++) { 
     long prime = Iterables.get(primeFactors.elementSet(), i); 
     int count = primeFactors.count(prime); 
     // ++start; remove it 

     for (int c = 0; c <= count; c++) { 
      long factor = ArithmeticUtils.pow(prime, c); 
      divisors.add(lastFactor * factor); 
      generateDivisorsTraditional(i+1, lastFactor * factor, primeFactors, divisors); // replaced start -> i+1 
     } 
    } 
} 

private static void generateDivisorsStream(int start, long lastFactor, Multiset<Long> primeFactors, Set<Long> divisors) { 
    IntStream.range(start, primeFactors.elementSet().size()) 
      .forEach((int i) -> { 
       long prime = Iterables.get(primeFactors.elementSet(), i); 
       int count = primeFactors.count(prime); 
       IntStream.range(0, count + 1) 
         .forEach((int c) -> { 
          long factor = ArithmeticUtils.pow(prime, c); 
          divisors.add(lastFactor * factor); 
          generateDivisorsStream(i+1, lastFactor * factor, primeFactors, divisors); 
         }); 
      }); 
} 

public static void main(String[] args) { 
    Multiset<Long> m = HashMultiset.create(); 
    m.add(1L, 1); 
    m.add(2L, 1); 
    m.add(5L, 1); 
    Set<Long> divisors = new HashSet<>(); 
    generateDivisorsTraditional(1, 1, m, divisors); 
    System.out.println("Traditional=> "+divisors); 
    divisors = new HashSet<>(); 
    generateDivisorsStream(1, 1, m, divisors); 
    System.out.println("Stream=> "+divisors); 
} 

它打印:

Traditional=> [1, 2, 5, 10] 
Stream=> [1, 2, 5, 10] 
+0

是不是覺得應該是'我+ 1'由我應更換'start'?我用'i'檢查過,它不可避免地給了我'StackOverflowError'。 –

+0

@TapasBose你是對的,'開始' - >'i + 1',編輯過 –