Algoritmo de tamiz de Eratóstenes en C++

Jinku Hu 12 octubre 2023
Algoritmo de tamiz de Eratóstenes en C++

Este artículo explicará cómo implementar el algoritmo de tamiz de eratóstenes en C++.

Implementar el algoritmo Sieve of Eratosthenes usando el contenedor std::vector en C++

El tamiz de Eratóstenes es uno de los tamices de números primos, que representa algoritmos relativamente eficientes para encontrar números primos. Existen múltiples algoritmos adecuados para diferentes rangos de números primos y también tienen características de rendimiento contrastantes.

El tamiz de Eratóstenes puede considerarse el más fácil de implementar y es bastante eficiente en rangos más pequeños. Aunque su complejidad de tiempo de ejecución es O(N loglogN), funciona mejor en rangos más pequeños.

Este artículo implementará este algoritmo utilizando el método más sencillo para adaptarse al artículo introductorio. El algoritmo toma el valor entero y encuentra todos los números primos menores o iguales al entero dado.

Al principio, construimos un array de valores booleanos que tiene el mismo tamaño que el entero dado e inicializamos cada elemento para que tenga un valor true.

Luego iteramos a través de esta matriz de elementos y almacenamos un valor false si el elemento dado tiene un índice compuesto. Accedemos a los índices del array calculando los múltiplos de primos consecutivos comenzando desde el más pequeño - 2, y detenemos la iteración una vez que el cuadrado del primo dado es mayor que el entero de entrada - n. Los pasos anteriores se implementan utilizando los bucles for anidados en la función printPrimesLessThanN.

Finalmente, recorremos este vector e imprimimos los índices de elementos que tienen un valor true almacenado. Tenga en cuenta que la última operación es manejada por el bucle for al final de la función printPrimesLessThanN. También proporcionamos el código del controlador en la función main para aceptar el número entero que denota el límite superior del usuario y validar la entrada hasta que se pasa a la función printPrimesLessThanN.

#include <cstring>
#include <iostream>
#include <limits>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::vector;

void printPrimesLessThanN(unsigned long long n) {
  vector<bool> table(n, true);

  for (unsigned long long p = 2; p * p < n; p++) {
    if (table[p] == true) {
      for (unsigned long long i = p * p; i < n; i += p) table[i] = false;
    }
  }

  for (unsigned long long p = 2; p < n; p++)
    if (table[p]) cout << p << " ";
}

int main() {
  unsigned long long integer;

  while (true) {
    cout << "Enter integer: ";
    if (cin >> integer) {
      break;
    } else {
      cout << "Enter a valid integer value!\n";
      cin.clear();
      cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
  }

  cout << "Following prime numbers are smaller than given integer: \n";

  printPrimesLessThanN(integer);

  return EXIT_SUCCESS;
}

Producción :

Enter integer: 30
Following prime numbers are smaller than given integer:
2 3 5 7 11 13 17 19 23 29

El fragmento de código anterior es un ejemplo funcional que se puede optimizar con varios métodos, como explotar la simultaneidad en el programa, dividir y almacenar el array en la memoria para optimizar el acceso a los datos o utilizar otros conocimientos algorítmicos. Sin embargo, hay una pequeña idea que puede ahorrar múltiplos de tiempo de ejecución para esta implementación sin hacer grandes cambios, y es almacenar valores true / false en el vector de char.

Como puede observar al ejecutar múltiples pruebas en números más grandes, el tipo bool funciona bastante peor que el tipo integral como char o incluso int. El siguiente ejemplo de código muestra el escenario de referencia simple para ambas versiones de la función - printPrimesLessThanN e imprime el tiempo transcurrido al final del programa.

#include <sys/time.h>

#include <cstring>
#include <iostream>
#include <limits>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::vector;

float time_diff(struct timeval *start, struct timeval *end) {
  return (end->tv_sec - start->tv_sec) + 1e-6 * (end->tv_usec - start->tv_usec);
}

void printPrimesLessThanN(unsigned long long n) {
  vector<bool> table(n, true);
  struct timeval start {};
  struct timeval end {};

  gettimeofday(&start, nullptr);

  for (unsigned long long p = 2; p * p < n; p++) {
    if (table[p] == true) {
      for (unsigned long long i = p * p; i < n; i += p) table[i] = false;
    }
  }
  gettimeofday(&end, nullptr);

  printf("printPrimesLessThanN1: %0.8f sec\n", time_diff(&start, &end));
}

void printPrimesLessThanN2(unsigned long long n) {
  vector<char> table(n, 1);
  struct timeval start {};
  struct timeval end {};

  gettimeofday(&start, nullptr);

  for (unsigned long long p = 2; p * p < n; p++) {
    if (table[p] == 1) {
      for (unsigned long long i = p * p; i < n; i += p) table[i] = 0;
    }
  }
  gettimeofday(&end, nullptr);

  printf("printPrimesLessThanN2: %0.8f sec\n", time_diff(&start, &end));
}

int main() {
  unsigned long long integer;

  while (true) {
    cout << "Enter integer: ";
    if (cin >> integer) {
      break;
    } else {
      cout << "Enter a valid integer value!\n";
      cin.clear();
      cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
  }

  printPrimesLessThanN(integer);
  printPrimesLessThanN2(integer);

  return EXIT_SUCCESS;
}

Producción :

Enter integer: 1000000000
printPrimesLessThanN1: 47.39665985 sec
printPrimesLessThanN2: 10.11181545 sec
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Artículo relacionado - C++ Algorithm