Возможно, немного сложнее, но он работает до сих пор и использует, вероятно, самый быстрый (и самый маленький) генератор простых чисел, который я мог найти в Java.
Сначала мы получили генератор простых чисел, необходимый для проверки, является ли значение простым. Мы используем генератор (этот в 10 раз быстрее, чем простой метод), поэтому мы используем кэшированный список:
/**
* Sieve of Sundaram prime number generator
* Implementation following the Sieve of Sundaram to generate prime numbers
*
* @see http://en.wikipedia.org/wiki/Sieve_of_Sundaram
*/
static public class SundaramSievePrimeGenerator {
public String getName() { return "Sieve of Sundaram generator"; }
public int[] findPrimes(int max) {
int n = max/2;
boolean[] isPrime = new boolean[max];
Arrays.fill(isPrime, true);
for (int i=1; i<n; i++) {
for (int j=i; j<=(n-i)/(2*i+1); j++) {
isPrime[i+j+2*i*j] = false;
}
}
int[] primes = new int[max];
int found = 0;
if (max > 2) {
primes[found++] = 2;
}
for (int i=1; i<n; i++) {
if (isPrime[i]) {
primes[found++] = i*2+1;
}
}
return Arrays.copyOf(primes, found);
}
}
Тогда у нас есть два метода, необходимых для фактического получения списка простых множителей для n
:
/**
* Reuse an instance of the SundaramSievePrimeGenerator
*/
static public List<Integer> findPrimeFactors(int n, SundaramSievePrimeGenerator g) {
ArrayList<Integer> primeFactors = new ArrayList<Integer>();
int[] primes = g.findPrimes(n+1);
int v;
// debug
//System.out.print("** primes found : ");
//for (int a : primes) {
// System.out.print(" " + a);
//}
//System.out.println();
if (primes[primes.length-1] == n) {
primeFactors.add(n);
} else {
int max = primes.length - 1;
for (int i=max; i>=0; i--) {
primeFactors.add(primes[i]);
if (testPrimeFactor(n, primes[i], primes, i, primeFactors)) {
break; // we found our solution
}
primeFactors.clear();
}
}
return primeFactors;
}
/**
* Recursive method initially called by findPrimeFactors(n, g)
*/
static private boolean testPrimeFactor(int n, int v, int[] primes, int index, List<Integer> factors) {
int v2 = v * primes[index];
if (v2 == n) {
factors.add(primes[index]);
return true;
} else if (v2 > n) {
if (index > 0) {
return testPrimeFactor(n, v, primes, index-1, factors);
} else {
return false;
}
} else {
while (index > 0) {
factors.add(primes[index]);
if (testPrimeFactor(n, v2, primes, index, factors)) {
return true;
}
factors.remove(factors.size()-1); // no good, remove added prime
v2 = v * primes[--index];
}
return false; // at this point, we are still below n... so no good
}
}
И, наконец, наш тестовый пример:
int n = 1025;
SundaramSievePrimeGenerator generator = new SundaramSievePrimeGenerator();
List<Integer> factors = findPrimeFactors(n, generator);
if (factors.isEmpty()) {
System.out.println("No prime factors found for " + n);
} else {
System.out.println(n + " is composed of " + factors.size() + " prime factors");
int v = 1;
for (int i : factors) {
v *= i;
System.out.print(" " + i);
}
System.out.println(" = " + v);
}
Например, этот код выше выдаст:
1025 is composed of 3 prime factors
41 5 5 = 1025
И изменение n = 81
даст желаемый результат
81 is composed of 4 prime factors
3 3 3 3 = 81