GCD&素数打表&快速判断质数

GCD(求两数的最大公约数)

#include <cstdio>
__int64 GCD(__int64 a,__int64 b)//GCD
{
    if (a % b == 0)
       return b;
    else
       return GCD(b,a%b);
}
int main()
{
    __int64 a,b;
    __int64 ans;
    while (~scanf ("%I64d %I64d",&a,&b))
   {
      ans=GCD(a,b);
      printf ("%I64d\n",ans);
   }
   return 0;
}

 

素数打表

int su[1000005]={1,1};
for(int i=2;i<=1000000;i++)
{
    if(su[i]==1)
       continue;
    for(int j=i*2;j<=1000000;j+=i)
       su[j]=1;
}

 

 

快速判断质数

下面的转自[菜鸟专供|高手勿入] 快速判断质数

1、任何一个合数(都指正整数,下同),都是几个质数的乘积。例如:18 = 2 * 3 * 3

2、如果一个数N不能整除M,则N也不能整除M*i,i=1, 2, 3....。即,N%M != 0,则 N%(M*i)  != 0。例如,N不能整除2,那么N也不能整除6。因为,如果N能整除6,即,N%6 = 0,也就是 N%(2*3) = 0,也就是N能整除2,与前面矛盾。

3、如果N不是质数,那么N有满足1<d<=sqrt(N)(N的平方根)的一个质数因子 d 存在。因为如果N不是质数,根据条例1,N肯定可以分解为一堆质数的和,即肯定存在一个质数因子。如果找不到,那就说明N是质数,只能被1和自己本身整除。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

A、依照判断素数的概念,我们可以从2~N-1,依次去除,看余数是否为0,复杂度为O(N)

B、改进一下,先判断 N%2 是否为0,如果不为0,即 N%(2*i) != 0(前面的条例2),所以只要再判断 3~N-1 之间的奇数即可,复杂度减半!为O(N/2)

同理,可以再判断 N%3 是否为0,如果不为0,则可以去掉后面的 3*i

C、其实,并不需要一直整除到N-1,而只要整除到 sqrt(N) 即可。如果 a < sqrt(N), b<sqrt(N),那么 a * b < sqrt(N)*sqrt(N) = N。如果b = N/a,那么b肯定是>=sqrt(N)。所以,只要判断小于等于sqrt(N)的数即可,再判断大于sqrt(N)的数就是在浪费时间了。

D、结合前面的 B 和 C,我们就可以先判断 N%2 是否为0,然后再判断 3~sqrt(N) 之间的奇数即可,复杂度为O(sqrt(N)/2)

E、根据条例3,如果N是质数,则N只能被1和N整除,如果N不是质数,那一定存在1<d<=sqrt(N)的一个质数因子。那么我们就可以取 2~sqrt(N) 之间的所有质数d,依次判断N%d 是否为0。如果判断均不等于0,就说明不存在这样的一个质数,也就是说N只能被1和本身整除,即N是质数。

注意: 如果没有特殊说明, 以下讨论的都是针对n为素数时的时间复杂度

1. 根据概念判断:

如果一个正整数只有两个因子, 1和p,则称p为素数.

bool isPrime(int n)
{
if(n < 2) return false;

for(int i = 2; i < n; ++i)
if(n%i == 0) return false;

return true;
}


时间复杂度O(n).


2. 改进, 去掉偶数的判断

bool isPrime(int n)
{
if(n < 2) return false;
if(n == 2) return true;

for(int i = 3; i < n; i += 2)
if(n%i == 0) return false;

return true;
}


时间复杂度O(n/2), 速度提高一倍.

3. 进一步减少判断的范围

定理: 如果n不是素数, 则n有满足1<d<=sqrt(n)的一个因子d.
证明: 如果n不是素数, 则由定义n有一个因子d满足1<d<n.
如果d大于sqrt(n), 则n/d是满足1<n/d<=sqrt(n)的一个因子.

bool isPrime(int n)
{
if(n < 2) return false;
if(n == 2) return true;

for(int i = 3; i*i <= n; i += 2)
if(n%i == 0) return false;

return true;
}


时间复杂度O(sqrt(n)/2), 速度提高O((n-sqrt(n))/2).


4. 剔除因子中的重复判断.
例如: 11%3 != 0 可以确定 11%(3*i) != 0.

定理: 如果n不是素数, 则n有满足1<d<=sqrt(n)的一个"素数"因子d.
证明: I1. 如果n不是素数, 则n有满足1<d<=sqrt(n)的一个因子d.
I2. 如果d是素数, 则定理得证, 算法终止.
I3. 令n=d, 并转到步骤I1.

由于不可能无限分解n的因子, 因此上述证明的算法最终会停止.

// primes[i]是递增的素数序列: 2, 3, 5, 7, ...
// 更准确地说primes[i]序列包含1->sqrt(n)范围内的所有素数

bool isPrime(int primes[], int n)
{
if(n < 2) return false;

for(int i = 0; primes[i]*primes[i] <= n; ++i)
if(n%primes[i] == 0) return false;

return true;
}


假设n范围内的素数个数为PI(n), 则时间复杂度O(PI(sqrt(n))).
函数PI(x)满足素数定理: ln(x)-3/2 < x/PI(x) < ln(x)-1/2, 当x >= 67时.
因此O(PI(sqrt(n)))可以表示为O(sqrt(x)/(ln(sqrt(x))-3/2)),
O(sqrt(x)/(ln(sqrt(x))-3/2))也是这个算法的空间复杂度.


5. 构造素数序列primes[i]: 2, 3, 5, 7, ...

由4的算法我们知道, 在素数序列已经被构造的情况下, 判断n是否为素数效率很高;

但是, 在构造素数序列本身的时候, 是否也可是达到最好的效率呢?

事实上这是可以的! -- 我们在构造的时候完全可以利用已经被构造的素数序列!

假设我们已经我素数序列: p1, p2, .. pn

现在要判断pn+1是否是素数, 则需要(1, sqrt(pn+1)]范围内的所有素数序列,

而这个素数序列显然已经作为p1, p2, .. pn的一个子集被包含了!

// 构造素数序列primes[]
 

void makePrimes(int primes[], int num)
{
int i, j, cnt;

primes[0] = 2;
primes[1] = 3;

for(i = 5, cnt = 2; cnt < num; i += 2)
{
int flag = true;
for(j = 1; primes[j]*primes[j] <= i; ++j)
{
if(i%primes[j] == 0)
{
flag = false; break;
}
}
if(flag) primes[cnt++] = i;
}
}


makePrimes的时间复杂度比较复杂, 而且它只有在初始化的时候才被调用一次.在一定的应用范围内, 我们可以把近似认为makePrimes需要常数时间.在后面的讨论中, 我们将探讨一种对计算机而言更好的makePrimes方法.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值