Zeef van Eratosthenes in Python & C++

⚡ Slimme samenvatting

De zeef van Eratosthenes is een klassiek priemgetalalgoritme dat samengestelde getallen filtert door iteratief veelvouden van elk priemgetal te markeren, waardoor alleen priemgetallen binnen een gekozen bovengrens overblijven voor snelle opzoeking.

  • 🔢 Kernidee: Markeer de veelvouden van elk priemgetal, beginnend bij 2, om de priemgetallen tot en met n te isoleren.
  • 🧮 Lusbegrenzing: Herhaal de berekening alleen tot en met de wortel van n, omdat grotere factoren al zijn geëlimineerd.
  • ⚡ Tijdscomplexiteit: Het algoritme werkt in O(n log log n), wat voor praktische bereiken nagenoeg lineair is.
  • ✅ Gesegmenteerde zeef: Door het bereik in blokken op te splitsen, wordt het hulpgeheugen gereduceerd van O(n) naar O(√n).
  • 🧪 Gebruik Gevallen: Cryptografie, hashing, competitief programmeren en getaltheorie zijn afhankelijk van snelle priemgetalgeneratie.

Zeef van Eratosthenes in Python

Wat is de zeef van Eratosthenes?

De zeef van Eratosthenes is de eenvoudigste priemgetallenzeef. Het is een priemgetallenalgoritme dat gebruikt wordt om alle priemgetallen binnen een bepaalde limiet te vinden. Er bestaan ​​verschillende priemgetallenzeven, waaronder de zeef van Eratosthenes, de zeef van Atkin en de zeef van Sundaram.

Het woord "zeef" verwijst naar een werktuig dat stoffen filtert. In dezelfde geest verwijst het zeefalgoritme in Python In andere talen verwijst het naar een methode die priemgetallen uit een lijst met gehele getallen filtert.

Dit algoritme filtert priemgetallen met behulp van een iteratieve aanpak. Het filterproces begint met het kleinste priemgetal. Een priemgetal is een natuurlijk getal groter dan 1 dat slechts twee delers heeft, namelijk 1 en het getal zelf. Numbers Getallen die geen priemgetallen zijn, worden samengestelde getallen genoemd.

Waarom de zeef van Eratosthenes gebruiken?

Bij de zeefmethode van Eratosthenes wordt eerst een klein priemgetal geselecteerd, waarna alle veelvouden daarvan worden weggefilterd. Het proces wordt in een lus uitgevoerd over een bepaald bereik, waarbij alle priemgetallen tot en met n efficiënt worden gegenereerd zonder dat voor elke kandidaat een proefdeling hoeft te worden uitgevoerd.

Dit maakt de zeefmethode sneller dan het controleren op primaliteit van één getal tegelijk. De methode wordt veel gebruikt in de getaltheorie, cryptografie, hashing en competitief programmeren, waar snel veel priemgetallen gegenereerd moeten worden.

Bijvoorbeeld:

Laten we het getallenbereik van 2 tot en met 10 nemen.

Zeef van Eratosthenes-algoritme

Na toepassing van de zeef van Eratosthenes levert dit de lijst met priemgetallen 2, 3, 5, 7 op.

Zeef van Eratosthenes-algoritme

Algoritme Zeef van Eratosthenes

Hier is het algoritme voor de zeef van Eratosthenes:

Stap 1) Maak een lijst met getallen van 2 tot en met het gegeven bereik n. We beginnen met 2 omdat dit het kleinste en eerste priemgetal is.

Stap 2) Selecteer het kleinste getal in de lijst, x (aanvankelijk is x gelijk aan 2), doorloop de lijst en filter de bijbehorende samengestelde getallen door alle veelvouden van het geselecteerde getal te markeren.

Stap 3) Kies vervolgens het volgende priemgetal of het kleinste ongemarkeerde getal in de lijst en herhaal stap 2.

Stap 4) Herhaal de vorige stap totdat de waarde van x kleiner is dan of gelijk aan de wortel van n (x<=Algoritme Zeef van Eratosthenes).

Let op: De wiskundige redenering is vrij eenvoudig. Het getallenbereik n kan als volgt worden ontbonden:

n = a * b

Nogmaals, n = Algoritme Zeef van Eratosthenes * Algoritme Zeef van Eratosthenes

= (factor kleiner dan Algoritme Zeef van Eratosthenes) * (factor groter dan Zeef van Eratosthenes-algoritme)

Dus minstens één van de priemfactoren of beide moeten <= zijn Algoritme Zeef van EratosthenesDaarom, door omhoog te gaan naar Algoritme Zeef van Eratosthenes zal genoeg zijn.

Stap 5) Na deze vier stappen zullen de overgebleven, niet-gemarkeerde getallen alle priemgetallen in het gegeven bereik n zijn.

Uitgewerkt voorbeeld

Voorbeeld:

Laten we een voorbeeld nemen en kijken hoe het werkt.

Voor dit voorbeeld zoeken we de lijst met priemgetallen van 2 tot en met 25 op. Dus n = 25.

Stap 1) In de eerste stap nemen we een lijst met getallen van 2 tot en met 25, aangezien we n = 25 hebben gekozen.

Algoritme Zeef van Eratosthenes

Stap 2) Vervolgens selecteren we het kleinste getal uit de lijst, x. Aanvankelijk is x = 2, omdat dit het kleinste priemgetal is. Daarna doorlopen we de lijst en markeren we de veelvouden van 2.

De veelvouden van 2 voor de gegeven waarde van n zijn: 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24.

Zeef van Eratosthenes-algoritme

Let op: Blauw geeft het geselecteerde getal aan, en roze geeft de uitgesloten veelvouden aan.

Stap 3) Vervolgens kiezen we het volgende kleinste ongemarkeerde getal, namelijk 3, en herhalen we de laatste stap door de veelvouden van 3 te markeren.

Zeef van Eratosthenes-algoritme

Stap 4) We herhalen stap 3 op dezelfde manier totdat x = Zeef van Eratosthenes-algoritme of 5.

Zeef van Eratosthenes-algoritme

Stap 5) De overige niet-gemarkeerde getallen zijn de priemgetallen van 2 tot en met 25.

Zeef van Eratosthenes-algoritme

Pseudo-Code

De volgende pseudocode geeft de basisstructuur van de Zeef van Eratosthenes weer voordat we deze naar daadwerkelijke code vertalen.

Begin
	Declare a boolean array of size n and initialize it to true
	For all numbers i : from 2 to sqrt(n)
     		IF bool value of i is true THEN
         			i is prime
         			For all multiples of i (i<n)
             			mark multiples of i as composite
Print all unmarked numbers
End

Zeef van Eratosthenes C/C++ Code Voorbeeld

Hieronder staat een complete C++ Implementatie van de Zeef van Eratosthenes die alle priemgetallen tot een gekozen bovengrens afdrukt.

#include <iostream>
#include <cstring>
using namespace std;
void Sieve_Of_Eratosthenes(int n)
{
    // Create and initialize a boolean array
    bool primeNumber[n + 1];
    memset(primeNumber, true, sizeof(primeNumber));
    for (int j = 2; j * j <= n; j++) {
        if (primeNumber[j] == true) {
            // Update all multiples of i as false
            for (int k = j * j; k <= n; k += j)
                primeNumber[k] = false;
        }
    }
    for (int i = 2; i <= n; i++)
        if (primeNumber[i])
            cout << i << " ";
}
int main()
{
    int n = 25;
    Sieve_Of_Eratosthenes(n);
    return 0;
}

Output:

2 3 5 7 11 13 17 19 23

Zeef van Eratosthenes Python Programmavoorbeeld

De volgende Python Het programma implementeert hetzelfde algoritme met behulp van een booleanlijst en een while-lus.

def SieveOfEratosthenes(n):
# Create a boolean array
	primeNumber = [True for i in range(n+2)]
	i = 2
	while (i * i <= n):
		if (primeNumber[i] == True):
			# Update all multiples of i as false
			for j in range(i * i, n+1, i):
				primeNumber[j] = False
		i += 1
	for i in range(2, n):
		if primeNumber[i]:
			print(i)
n = 25
SieveOfEratosthenes(n)

Output:

2
3
5
7
11
13
17
19
23

Gesegmenteerde zeef

We hebben gezien dat de zeef van Eratosthenes een lus door het hele getallenbereik doorloopt. Daarom is er O(n) geheugenruimte nodig om de getallen op te slaan. De situatie wordt ingewikkeld wanneer we priemgetallen in een enorm bereik proberen te vinden, omdat het niet haalbaar is om zo'n groot geheugenblok toe te wijzen voor een grotere n.

Het algoritme kan worden geoptimaliseerd door een aantal nieuwe functies te introduceren. Het idee is om het getallenbereik in kleinere segmenten te verdelen en priemgetallen in die segmenten één voor één te berekenen. Dit is een efficiënte manier om de ruimtecomplexiteit te verminderen. Deze methode wordt een gesegmenteerde zeef.

Optimalisatie kan op de volgende manier worden bereikt:

  1. Gebruik een eenvoudige zeef om priemgetallen van 2 tot en met XNUMX te vinden. Gesegmenteerde zeef en sla ze op in een array.
  2. Verdeel het bereik [0…n-1] in maximaal meerdere segmenten van grootte Gesegmenteerde zeef.
  3. Doorloop elk segment en markeer de veelvouden van de priemgetallen die in stap 1 zijn gevonden. Deze stap vereist O(Gesegmenteerde zeef) maximaal.

De reguliere zeef vereist O(n) extra geheugenruimte, terwijl de gesegmenteerde zeef O(Gesegmenteerde zeef), wat een aanzienlijke verbetering is voor een grote n. De methode heeft echter ook een nadeel, omdat de tijdscomplexiteit er niet door verbetert.

Complexiteitsanalyse

Inzicht in zowel ruimtelijke als temporele complexiteit helpt je bij het kiezen tussen de reguliere zeefmethode en de gesegmenteerde zeefmethode voor een gegeven probleemgrootte.

Ruimtecomplexiteit:

Het eenvoudige zeefalgoritme van Eratosthenes vereist O(n) geheugenruimte. De gesegmenteerde zeef vereist O(Complexiteitsanalyse) hulpruimte.

Tijdscomplexiteit:

De tijdscomplexiteit van een standaard Zeef van Eratosthenes-algoritme is O(n*log(log(n))). De redenering achter deze complexiteit wordt hieronder besproken.

Voor een gegeven getal n is de tijd die nodig is om een ​​samengesteld getal (dat wil zeggen, een niet-priemgetal) te markeren constant. Het aantal keren dat de lus wordt uitgevoerd is dus gelijk aan:

n/2 + n/3 + n/5 + n/7 + ……∞

= n * (1/2 + 1/3 + 1/5 + 1/7 +…….∞)

De harmonische reeks van de som van de priemgetallen kan worden afgeleid als log(log(n)):

(1/2 + 1/3 + 1/5 + 1/7 +…….∞) = log(log(n))

De tijdscomplexiteit zal dus zijn:

T(n) = n * (1/2 + 1/3 + 1/5 + 1/7 + ……∞)

= n * log(log(n))

De tijdscomplexiteit is dus O(n * log(log(n))).

Vervolgens leer je meer over Driehoek van Pascal.

Veelgestelde vragen

Elk samengesteld getal n kan worden geschreven als een product van twee factoren, waarbij minstens één factor kleiner dan of gelijk aan de wortel van n moet zijn. Het is niet nodig om veelvouden na dit punt nog te markeren, omdat alle samengestelde getallen dan al zijn uitgesloten.

De reguliere zeefmethode wijst O(n) geheugen toe om elk getal te markeren, terwijl de gesegmenteerde zeefmethode het bereik opsplitst in blokken van grootte √n en geheugen hergebruikt. De gesegmenteerde versie is te verkiezen wanneer n erg groot is en het RAM-geheugen beperkt is.

Het proces heeft een looptijd van O(n log log n), wat bijna lineair is. Het genereren van alle priemgetallen onder de tien miljoen duurt slechts een fractie van een seconde op een moderne laptop, waardoor de zeefmethode de snelste praktische keuze is voor kleine tot middelgrote bereiken.

Moderne AI-acceleratoren versnellen het zoeken naar grote priemgetallen door zeefprocessen te paralleliseren op GPU's en TPU's. Machine learning-modellen helpen ook bij het voorspellen van veelbelovende kandidaatbereiken, waardoor de werklast voor Miller-Rabin en andere primaliteitstesten die worden gebruikt bij het genereren van RSA-sleutels, wordt verminderd.

Ja. AI-tutoren genereren stapsgewijze instructies. tracZe visualiseren samengestelde eliminatie, suggereren optimalisaties zoals wielfactorisatie en leggen bewijzen interactief uit. Ze helpen leerlingen intuïtie te ontwikkelen voor de grenzen van harmonische reeksen en de complexiteitsargumenten achter de zeefmethode.

Vat dit bericht samen met: