Método de tamiz de números primos (explicación detallada del tamiz Angstrom y el tamiz lineal)

La forma más sencilla de encontrar números primos es, por supuesto, recorrerlos uno por uno, recorrer cada número por turno y luego juzgar si es un número primo o no. Entonces, el núcleo del problema vuelve a juzgar los números primos. Entonces, ¿cómo juzgar si un número es primo?

Solo hay una propiedad de un número primo, es decir, 1 y él mismo solo tienen dos factores , y solo podemos usar esta propiedad para juzgar un número primo. Entonces se puede imaginar que si queremos juzgar si n es un número primo, podemos pasar de 2 a n-1. Si ninguno de los números n-1 puede dividir n, entonces significa que n es un número primo. Recuerdo correctamente que apareció en los ejercicios del lenguaje C. En definitiva, es muy sencillo y se puede decir que es el algoritmo más sencillo.

Método de tamiz Angstrom

El algoritmo de Eratóstenes que vamos a presentar hoy es un método que él inventó para filtrar números primos. Por conveniencia, generalmente lo llamamos tamiz de Escherichia o tamiz . La idea del método del tamiz de Escherichia es muy simple, es decir, utilizar los números primos que han sido filtrados para filtrar todos los números que pueden ser divisibles por él. Estos números primos son como un tamiz para filtrar los números naturales, y los números que quedan después de ser tamizados son naturalmente números que no pueden ser divisibles por los números primos anteriores. Según la definición de números primos, estos números restantes también son números primos.

Por ejemplo, si queremos filtrar todos los números primos dentro de 100, sabemos que 2 es el número primo más pequeño, podemos usar 2 para filtrar primero todos los números pares. Luego regrese a 3, 3 es el primer número que queda después de ser tamizado por 2, y también es un número primo. Luego usamos 3 para tamizar todos los números que son divisibles por 3. Después del tamizado, continuamos atravesando hacia atrás. El primer número encontrado es 7, por lo que 7 también es un número primo. Repetimos el proceso anterior hasta que finalice el recorrido. Al final tenemos todos los números primos hasta 100.

Si aún no lo entiendes del todo, puedes mirar la siguiente animación, que restaura todo el proceso con mucha claridad.

La complejidad del tiempo es O (nlognlongn)

#include<iostream>
using namespace std;
const int N = 1e7;
int prime[N + 1];
bool visit[N + 1];
//素数筛
//埃式筛
int E_sieve(int n) {
	int k = 0;
	for (int i = 0; i < n; i++) visit[i] = false;
	// 1.普通
	/* for (int i = 2; i <= n; i++) {
		if (!visit[i]) {
			prime[k++] = i;
			for (int j = i * 2; j <= n; j+=i) { // i的倍数筛选调
				visit[j] = true;
			}
		}
	}*/
	//2.优化 有些数可能会被多筛几遍 这样会影响时间复杂度
	for (int i = 2; i * i <= n; i++)
		if (!visit[i])
			for (int j = i * i; j <= n; j += i) visit[j] = true;
	int k = 0;
	for (int i = 2; i <= n; i++) { // i * i 前面的合数被更小的素数划掉了
		if (!visit[i]) prime[k++] = i;
	}
	return k; // 1~n中的素数
}


int main() {
	return 0;
}

Tamiz Euler

El método de criba de Euler también se denomina método de criba lineal, que puede cribar números primos en 1 ~ n en tiempo lineal O (n).

Por ejemplo, el número compuesto 6 se puede tachar con los números primos 2 y 3. En este momento, solo necesitamos tachar claramente el número primo más pequeño.

#include<iostream>
using namespace std;
const int N = 1e7;
int prime[N + 1];
bool visit[N + 1];
//素数筛
//埃式筛
int E_sieve(int n) {
	int k = 0;
	for (int i = 0; i < n; i++) visit[i] = false;
	// 1.普通
	/* for (int i = 2; i <= n; i++) {
		if (!visit[i]) {
			prime[k++] = i;
			for (int j = i * 2; j <= n; j+=i) { // i的倍数筛选调
				visit[j] = true;
			}
		}
	}*/
	//2.优化 有些数可能会被多筛几遍 这样会影响时间复杂度
	for (int i = 2; i * i <= n; i++)
		if (!visit[i])
			for (int j = i * i; j <= n; j += i) visit[j] = true;
	int k = 0;
	for (int i = 2; i <= n; i++) { // i * i 前面的合数被更小的素数划掉了
		if (!visit[i]) prime[k++] = i;
	}
	return k; // 1~n中的素数
}
bool vis[N + 1];
int euler_sieve(int n) {
	int cnt = 0;
	memset(vis, 0, sizeof(vis));
	memset(prime, 0, sizeof(prime));

	for (int i = 2; i <= n; i++) {
		if (!vis[i]) prime[cnt++] = i;
		for (int j = 0; j < cnt; j++) {
			if (i * prime[j] > n) break; //越界的不需要了
			vis[i * prime[j]] = 1;//prime中全部的素数相乘一定式合数
			if (i % prime[j] == 0) break; //  每个合数只被最小质因子划掉 
		}
	}
	return cnt;
}
int main() {
	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/zhi6fui/article/details/128633372
Recomendado
Clasificación