质数(素数) 的判定和筛法

对于素数的判定:
引理:
若一个正整数N是合数,则存在一个能整除N的正整数T,其中 2 <= T <= sqrt(N)
证明:
反证法;如果正整数N是合数,那么能整除N的正整数M的范围是[sqrt(N) + 1, N - 1],因为M能整除N,所以N/M也能整除N,而N/M的范围是[2, sqrt(N)];N/M的最小值即N/(N - 1),因为N/M是正整数,所以N/(N - 1)最小是2;
那么根据引理,对于一个正整数N,如果所有的T(2 <= T <= sqrt(N))都不能整除N,那么N就不是合数,即N是素数;

素数的筛选:
1、Eratosthenes[ˌerəˈtɒsθəniːz]筛法,(埃拉托色尼筛法)
复杂度O(nloglogn)
思想:
任意x的倍数2x, 3x都不是素数,这符合素数的定义(只能被自身和1整除,2是最小的素数);
所以我们就可以标记,扫描到x时,如果x未被标记,就把2x,3x,4x都标记,那么未被标记的就是素数;其实发现它可以被优化,比如对于6,它被2标记过,也被3标记过,所以标记重复了,其实对于一个正整数x,它的小于x^2的倍数已经被比x更小的数标记了,所以我们只需要从xx开始打标记就行

void primes(int n){
	memset(v, 0, sizeof(v));
	for(int i = 2; i <= n; i++){
		if(!v[i]){
			printf("%d\n", v[i]);
			for(int j = i; j <= n / i; j++)
				v[i * j] = 1;
		}
	}
}

即使被优化了,Eratosthenes筛法依然存在重复标记的情况,对于12,它会被2标记,也会被3标记,根本原因是我们没有确定出唯一的产生12的方式;

2、线性筛(欧拉筛)
线性筛法通过从大到小累积质因子的方式标记每个合数,即12 = 3 * 2 * 2;
方法:
pre:设数组v记录每个数的最小质因子
1、依次考虑2 ~ N 的每个数 i;
2、若v[i] = i;证明 i 素数(即它的最小质因子为它本身),就把它保存起来;
3、扫描不大于v[i]的每个质数p,令v[i * p] = p;也就是在 i 的基础上累积一个质因子p;因为p <= v[i], 所以 p 就是合数 i * p的最小质因子;
最大的改进在于当prime[j] > v[i]时,break;

void primes(int n){
	memset(v,0, sizeof(v));
	m = 0;
	for(int i = 2; i <= n; i++){
		if(v[i] == 0){
			v[i] = i;
			prime[++m] = i;
		}
		for(int j = 1; j <= m; i++){
		//任何合数都是若干个素数的积,我们讲要从大到小累积质因子
		//如果一个质因子比v[i]大,说明不符合
			if(prime[j] > v[i] || prime[j] > n / i) break;
				v[i * prime[j]] = prime[j];
		}
	}
	for(int i = 0; i <= m; i++)
		printf("%d\n", prime[i]);
}

That’s all.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值