简体   繁体   中英

Prime factors using recursion in Java

I'm having trouble with recursion in java. So I have the following method and i should transform it only with recursion without any loop.

public static List<Integer> primesLoop(int n) {
    List<Integer> factors = new ArrayList<Integer>();
    int f = 2;
    while (f <= n)
        if (n % f == 0) {
            factors.add(f);
            n /= f;
        } else
            f++;
    return factors;
}

The recursive method should start with the same form:

public static List<Integer> primesRec(int n);

and also I should define help methods for the transformation The result is for example:

primesRec(900) -> prime factors of 900 : [2, 2, 3, 3, 5, 5]

You can often use simple transforms from the looping form to the recursive form. Local variables must generally be moved into a parameter. There is often two forms, one providing the user interface and another, often private , that actually performs the recursive function.

public static List<Integer> primesLoop(int n) {
    List<Integer> factors = new ArrayList<Integer>();
    int f = 2;
    while (f <= n) {
        if (n % f == 0) {
            factors.add(f);
            n /= f;
        } else {
            f++;
        }
    }
    return factors;
}

public static List<Integer> primesRecursive(int n) {
    // The creation of factors and the start at 2 happen here.
    return primesRecursive(new ArrayList<>(), n, 2);
}

private static List<Integer> primesRecursive(ArrayList<Integer> factors, int n, int f) {
    // The while becomes an if
    if (f <= n) {
        // This logic could be tuned but I've left it as-is to show it still holds.
        if (n % f == 0) {
            factors.add(f);
            // Make sure either n ...
            n /= f;
        } else {
            // ... or f changes to ensure no infinite recursion.
            f++;
        }
        // And we tail-recurse.
        primesRecursive(factors, n, f);
    }
    return factors;
}

public void test() {
    for (int n = 10; n < 100; n++) {
        List<Integer> loop = primesLoop(n);
        List<Integer> recursive = primesRecursive(n);
        System.out.println("Loop     : " + loop);
        System.out.println("Recursive: " + recursive);
    }
}

Notice the similarity between the two methods.

You can add f as an argument by overloading, and adding private method that does take it, and is invoked from the "main" public method.

In the private method, you have 3 cases:

  1. stop clause: n==1: create a new empty list
  2. n%f == 0: recurse with n'=n/f, f'=f, and add f to the list.
  3. n%f != 0: recurse with n'=n, f'=f+1, don't add anything to the list.

Code:

public static List<Integer> primesRecursive(int n) {
    return primesRecursive(n, 2);
 }

 //overload a private method that also takes f as argument:
 private static List<Integer> primesRecursive(int n, int f) {
     if (n == 1) return new ArrayList<Integer>();
     if (n % f == 0) {
         List<Integer> factors = primesRecursive(n/f, f);
         factors.add(f);
         return factors;
     } else
         return primesRecursive(n, f+1);
 }

As expected, invoking:

public static void main(String args[]) {
    System.out.println(primesRecursive(900));
}

Will yield:

[5, 5, 3, 3, 2, 2]

Note: If you want the factors in ascending order:

  1. switch ArrayList implementation to LinkedList in stop clause (for performance issues)
  2. add items with factors.add(0, f); instead factors.add(f)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM