Generazione di numeri primi in Java

1. Introduzione

In questo tutorial, mostreremo vari modi in cui possiamo generare numeri primi usando Java.

Se stai cercando di verificare se un numero è primo, ecco una guida rapida su come farlo.

2. Numeri primi

Cominciamo con la definizione principale. Un numero primo è un numero naturale maggiore di uno che non ha divisori positivi diversi da uno e se stesso.

Ad esempio, 7 è primo perché 1 e 7 sono i suoi unici fattori interi positivi, mentre 12 non lo è perché ha i divisori 3 e 2 oltre a 1, 4 e 6.

3. Generazione di numeri primi

In questa sezione vedremo come possiamo generare efficientemente numeri primi inferiori a un dato valore.

3.1. Java 7 e versioni precedenti - Brute Force

public static List primeNumbersBruteForce(int n) { List primeNumbers = new LinkedList(); for (int i = 2; i <= n; i++) { if (isPrimeBruteForce(i)) { primeNumbers.add(i); } } return primeNumbers; } public static boolean isPrimeBruteForce(int number) { for (int i = 2; i < number; i++) { if (number % i == 0) { return false; } } return true; } 

Come si può vedere, primeNumbersBruteForce è scorrere il numeri da 2 a n e semplicemente chiamando l'isPrimeBruteForce () metodo per verificare se un numero è primo o no.

Il metodo controlla la divisibilità di ogni numero per i numeri in un intervallo da 2 a numero-1 .

Se in qualsiasi momento incontriamo un numero divisibile, restituiamo falso. Alla fine, quando troviamo che il numero non è divisibile per nessuno dei suoi numeri precedenti, restituiamo true indicando che è un numero primo.

3.2. Efficienza e ottimizzazione

L'algoritmo precedente non è lineare e ha la complessità temporale di O (n ^ 2). Anche l'algoritmo non è efficiente e c'è chiaramente un margine di miglioramento.

Diamo un'occhiata alla condizione nel metodo isPrimeBruteForce () .

Quando un numero non è un numero primo, questo numero può essere scomposto in due fattori e cioè un e b cioè numero = a * b. Se sia a che b fossero maggiori della radice quadrata di n , a * b sarebbe maggiore di n .

Quindi almeno uno di questi fattori deve essere minore o uguale alla radice quadrata di un numero e per verificare se un numero è primo, dobbiamo solo verificare i fattori inferiori o uguali alla radice quadrata del numero controllato.

I numeri primi non possono mai essere un numero pari poiché i numeri pari sono tutti divisibili per 2.

Inoltre, i numeri primi non possono mai essere un numero pari poiché i numeri pari sono tutti divisibili per 2.

Tenendo presente le idee sopra, miglioriamo l'algoritmo:

public static List primeNumbersBruteForce(int n) { List primeNumbers = new LinkedList(); if (n >= 2) { primeNumbers.add(2); } for (int i = 3; i <= n; i += 2) { if (isPrimeBruteForce(i)) { primeNumbers.add(i); } } return primeNumbers; } private static boolean isPrimeBruteForce(int number) { for (int i = 2; i*i < number; i++) { if (number % i == 0) { return false; } } return true; } 

3.3. Utilizzando Java 8

Vediamo come riscrivere la soluzione precedente utilizzando gli idiomi di Java 8:

public static List primeNumbersTill(int n) { return IntStream.rangeClosed(2, n) .filter(x -> isPrime(x)).boxed() .collect(Collectors.toList()); } private static boolean isPrime(int number) { return IntStream.rangeClosed(2, (int) (Math.sqrt(number))) .filter(n -> (n & 0X1) != 0) .allMatch(n -> x % n != 0); } 

3.4. Usando il setaccio di Eratostene

C'è ancora un altro metodo efficiente che potrebbe aiutarci a generare numeri primi in modo efficiente, e si chiama Sieve Of Eratosthenes. La sua efficienza temporale è O (n logn).

Diamo un'occhiata ai passaggi di questo algoritmo:

  1. Crea un elenco di numeri interi consecutivi da 2 a n : (2, 3, 4,…, n)
  2. Inizialmente, sia p uguale a 2, il primo numero primo
  3. A partire da p , contare in incrementi di pe contrassegnare ciascuno di questi numeri maggiore di p nella lista. Questi numeri saranno 2p, 3p, 4p, ecc .; notare che alcuni di essi potrebbero essere già stati contrassegnati
  4. Trova il primo numero maggiore di p nell'elenco che non è contrassegnato. Se non c'era un tale numero, fermati. Altrimenti, sia ora p uguale a questo numero (che è il primo numero successivo) e ripeti dal passaggio 3

Alla fine, quando l'algoritmo termina, tutti i numeri nell'elenco che non sono contrassegnati sono i numeri primi.

Ecco come appare il codice:

public static List sieveOfEratosthenes(int n) { boolean prime[] = new boolean[n + 1]; Arrays.fill(prime, true); for (int p = 2; p * p <= n; p++) { if (prime[p]) { for (int i = p * 2; i <= n; i += p) { prime[i] = false; } } } List primeNumbers = new LinkedList(); for (int i = 2; i <= n; i++) { if (prime[i]) { primeNumbers.add(i); } } return primeNumbers; } 

3.5. Esempio di lavoro del setaccio di Eratostene

Vediamo come funziona per n = 30.

Considera l'immagine sopra, ecco i passaggi effettuati dall'algoritmo:

  1. Il ciclo inizia con 2, quindi lasciamo 2 non contrassegnato e contrassegniamo tutti i divisori di 2. È contrassegnato nell'immagine con il colore rosso
  2. Il ciclo si sposta su 3, quindi lasciamo 3 non contrassegnato e contrassegniamo tutti i divisori di 3 non ancora contrassegnati. È contrassegnato nell'immagine con il colore verde
  3. Il ciclo si sposta su 4, è già segnato, quindi continuiamo
  4. Il ciclo si sposta su 5, quindi lasciamo 5 non contrassegnato e contrassegniamo tutti i divisori di 5 non ancora contrassegnati. È contrassegnato nell'immagine con il colore viola
  5. Continuiamo i passaggi precedenti fino a quando non viene raggiunto il loop uguale alla radice quadrata di n

4. Conclusione

In questo breve tutorial, abbiamo illustrato i modi in cui possiamo generare numeri primi fino al valore "N".

L'implementazione di questi esempi può essere trovata su GitHub.