素数筛选方法,O(n)

素数筛选的方法很多,这里的方法和其他方法有相似的地方,都是标记合数,然后使用前面找到的素数进行再次的筛选,但是这个方法有它自己的特殊的地方,对于每一个合数,它只会标记一次,所以这样的话就能达到哦O(n)的效果。在这里,我们先贴上代码,然后进行证明。

int prime_len;
int primes[100000];
bool gash[100000];
void initPrimes(int n) {
	memset(gash , 0 , sizeof(gash));
	prime_len = 0;
	for (int i=2 ; i<=n ; i++) {
		if (!gash[i]) {
			primes[prime_len++] = i;
		}
		for (int j=0 ; j<prime_len && ((i * primes[j]) <= n) ; j++) {
			gash[i * primes[j]] = true;
			if (i % primes[j] == 0) break;
		}
	}
}

 

从上面我们可以看到,这个方法的筛选方式有这样两步:

1.        如果这个数没有被标记过,则这个数是一个素数,我们保存起来

2.        不管这个数是不是素数,使用这个数和前面找到的素数进行筛选,设i为当前的数,当i*p[j]<= n 并且p[j]不是i的因子,则筛选i*p[j]。

下面我们证明为什么这样是对的:

1.        首先我们证明这个算法是对的,及对于每一个合数,我们都能做上标记,对于每一个素数,我们都能找到

a)        对于任何一个素数p,我们都不可能使用两个数乘积进行标记,所以对于每一个素数,我们都是能找到的。

b)       对于任何一个合数m = p1a1p2a2…pmam,这里p1< p2 < … <pm,我们都能使用p1a1-1p2a2…pmam* p1进行筛选,所以对于每一个合数,我们都能筛选到做上标记。

2.        我们证明为什么每一个合数都只会标记一次

a)        m = x * qx , n = y * qy,这里 qx qy都是素数,且分别是m和n中的最小素数。当并且m != n,当我们使用两个不同的数进行筛选时,看看会不会标记相同的合数。使用m能找到的合数 x * qx* p[i],p[i]<qx,使用n能找到的合数y * qy * p[j],p[j] < qy,这里p是一个当前找到的素数序列。假设能找到相同的合数, 则x * qx * p[i] = y * qy * p[j]。因为m != n,则p[i] != p[j]。又因为qx, p[i] , qy, p[j]都是素数,且qx > p[i], qy > p[j],当qx = qy时,m中包含p[j]的因子,这样qx就不是m中最小的因子,则假设qx=qy不成立。当qx != qy,则当qx > qy,则m中包含了p[j]的因子,则假设qx >qy不成立。同样假设qx< qy,同样假设不成立,所以假设x* qx * p[i] = y * qy * p[j]不成立,所以只能标记一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值