2021-10-08

厄拉多塞筛法

原理:

厄拉多塞筛法(Eratosthenes Sieve)是一种求素数的方法,也称之为标记法,由古希腊数学家厄拉多塞提出。 它的原理是:给定一个数 n,从 2 开始依次将 n 以内所有的数放入一个足够大的数组中(此时数组的所有赋值均为0),给数组中下标为素数的倍数数组值标记(1),标记完成后,剩余未被标记的数为素数(即数组素数下标里的值为0),此时我们只需要输出数组值为0的数组的下标就能得到2~n以内的素数。(素数是从 2 开始的,除了1和本身没有其他的公因数的数)。

000000000000
12345678910...n

分析:

(1)第一个素数为2,此时我们只需要找到所有下标为2的倍数时数组的值,然后直接将此数组中的值赋值为1;此时一轮循环下去之后我们就能将2~n以内的数直接排除掉一半;

000101010100
12345678910...n

(2)第二个素数为3,此时我们同样只需要找到下标为3的倍数时数组的值,然后直接然后直接将此数组中的值赋值为1;此时又一轮下去直接减点原来的三分之一。

000101011100
12345678910...n

(3)然后依次下去最终能够排除将数组下标为合数的值直接标记为1,剩下数组中标记为0的数组下标就是素数;

....

代码:

#include<stdio.h>
int main() {//厄拉多塞筛法。
	int n;
	scanf("%d", &n);
	int nums[1001] = { 0 };//定义标记数组
	for (int i = 2; i <= n; i++) {
		if (nums[i] == 0) {//是素数就给标记为0,不是给标记为1
			/*printf("%d\n", i);*/
			//对每个素数的倍数进行寻找排除,当i=2时(2为素数),这时排除所有是2的倍数的数字,
			//i++之后3为素数,然后再排除为3的倍数的数字;
			//.......

            //在这里使用了加号是因为乘号要比加号在计算机中复杂。
			for (int j = i + i; j <= n; j += i) {
				nums[j] = 1;                    
			}
		}
	}
	for (int i = 2; i <=n; i++) {
		if (nums[i] == 0) {
			printf("%d ", i);
		}
	}
	return 0;
}

此时任意输入一个数n即可得到n以内的所有素数。

时间复杂度分析与对比:

一般而言我们首先想到的是双重for循环来计算素数问题,但是对于厄拉多塞筛法而言,虽然里面出现了二重循环,但是时间复杂度远远比二重循环下的要低,

一般做法时间复杂度:

我们用一个数count来计算for循环里面执行的次数来求得一般做法时间复杂度。

#include<stdio.h>
int main()
{
	int N, j,count=0;
	scanf("%d", &N);
	for (int i = 2; i <= N; i++)
	{
		for (j = 2; j < i; j++) {
			count++;
			if (i % j == 0) {
				count++;
				break;
			}
		}
		if (i == j) {
			//printf("%d ", i);
		}
	}
	printf("\n");
	printf("执行次数为:");
	printf("%d\n", count);
	printf("\n");
	return 0;
}

 执行结果:

取n=1000时,此时执行次数为78853,此时时间复杂度非常之高,

厄拉多塞筛法时间复杂度:

同样用一个count来计算for循环里面执行的次数。

代码:

#include<stdio.h>
int main() {//厄拉多塞筛法。
	int n;
	scanf("%d", &n);
	int count = 0;
	int nums[1001] = { 0 };//定义标记数组
	for (int i = 2; i <= n; i++) {
		if (nums[i] == 0) {//是素数就给标记为0,不是给标记为1
			/*printf("%d\n", i);*/
			//对每个素数的倍数进行寻找排除,当i=2时(2为素数),这时排除所有是2的倍数的数字,
			//i++之后3为素数,然后再排除为3的倍数的数字;
			//.......
			for (int j = i + i; j <= n; j += i) {

				nums[j] = 1;
				count++;
			}
		}
	}
	/*for (int i = 2; i <= n; i++) {
		if (nums[i] == 0) {
			printf("%d ", i);
		}
	}*/
	printf("\n");
	printf("执行次数为:");
	printf("%d", count);
	return 0;
}

执行结果:

 此时我们能看出当n=100时执行次数只有1958次,这就差不多相当于是O(n)的时间复杂度了

        通过两种方法的对比我们可以发现厄拉多塞筛法的高明之处,在时间复杂度上厄拉多塞筛法能够大大减少程序的时间复杂度。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值