判断两个数之间的素数

素数,指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数。大于1的自然数若不是素数,则称之为合数。
很自然通过定义我们就可以得到如何判断一个数是否是素数的算法
(python)

n=int(input())
isprime=1
for i in range(2,n):
    if n%i==0:
        isprime=0
        break
if isprime==1:
    print('Yes')
else:
    print('No')

在这里我们用1来表示素数,0表示非素数(即合数)。
(c语言)

#include <stdio.h>
int main()
{
   int n,i;
   scanf("%d",&n);
   int isprime=1;
   for (i=2;i<n;i++){
       if (n%i==0){
           isprime=1;
           break;
        }
}
   printf("%d",isprime);
   
   return 0;
}

现在我们知道了判断某一个数是否是素数的方法,那给你一串数该怎么判断呢,显然一个一个判断就行。
(python)
给定两个正整数m,n,输出区间[m,n]内的所有素数。

m,n=map(int,input().split())
isprime=1
for i in range(m,n+1):
    for j in range(2,i):
        if i%j==0:
            isprime=0
            break
    else:
        print(i) #输出所有的素数

这里使用了一个for-else语句,使代码看起来更简洁。为了遍历m和n之间的所有的数,使用了双重for循环。
(c语言)

#include <stdio.h>
int main()
{
    int M,N;
    int x;
    scanf("%d %d",&M,&N);

    for (x=M;x<N+1;x++){
        int i=2;
        int isprime=1;
        for (i=2;i<x;i++){
            if (x%i==0){ 
            isprime=0;
            break;}  //只要有比1大的因子,就一定不是素数,终止循环
        }
        if (isprime==1){
        printf("%d ",x);}
    }

    return 0;
}

现在我们已经知道如何简单的输出一定范围内的素数了,更进一步,你能不能输出前100个素数,以及第m个到第n个素数这些问题。
用python我们来做一个素数表,在这个表里的数都是素数。

n=int(input())
a=[i for i in range(2,n+1)]
b=[]
for i in range(len(a)):
    for j in range(2,a[i]):
        if a[i]%j==0 and a[i]!=2:
            break
    else:
        b.append(a[i])
print(b)

使用列表我们可以找出从1到n的素数,n取到很大时,就做出了一张很大的质数表,可以筛除那些合数。

a=[i for i in range(2,10000)]
b=[]
for i in range(len(a)):
    for j in range(2,a[i]):
        if a[i]%j==0 and a[i]!=2:
            break
    else:
        b.append(a[i])
m,n=map(int,input().split())
print(b[m-1:n])

在上面的代码里,我们先筛出了10000以内的素数,之后只需要在列表b里面找素数就可以了,如上就可以找出第m个素数到第n个素数。

显然先建一个列表这种方法很费力气,只是无聊的时候可以这样玩玩。

对于一般问题,我们已经可以成功解决了,但是有时候给我们的数据范围很大,这就要求我们得一定程度上优化算法。
(1)开平方法

如果大于1的整数a不能被所有不超过根号a的素数整除,那么a一定是素数。

n=int(input())
isprime=1
k=int(n**0.5)+1
for i in range(2,k):
    if n%i==0:
        isprime=0
        break
if isprime==1:
    print("Yes")
else:
    print('No')

不难得到原来的程序时间复杂度是O (n),现在优化到了O(\sqrt{n})。c语言代码类似,此处不再赘述。
(2)素数和6的关系

(大于等于5的)质数一定和6的倍数相邻,一定是6x-1或6x-1。利用这种特性。可以对整数进行筛选,只判断那些是6x-1或6x-1的整数是否为质数。

令x≥1,将大于等于5的自然数表示如下: ······6x-1,6x,6x+1,6x+2,6x+3,6x+4······(相邻6个数为一组)
在以上的数字中,6x、6x+2和6x+4是偶数,一定不是质数;6x+3可以分解为3(2x+1),不是质数,因此质数只能是6x-1和6x+1。

由以上结论,可以得出更简洁的代码。

n=int(input())     #n是大于等于5的正整数
isprime=1
k=int(n**0.5)+1
if n%6==1 or n%6==5:
    for i in range(2,k):
        if n%i==0:
            isprime=0
            break
    if isprime==1:
        print("Yes")
else:
    print('No')

时间复杂度由O(\sqrt{n})降到了原来的三分之一,因为我们只需要从三分之一的数里面来找素数,但时间复杂度只是在常数上做变化,n相当大时没有很大的贡献,类似于开平方法。

单个数的判断基本上已经定型了,但对于求1到n之间的所有素数,我们还有一些方法。
(3)埃氏筛法
已知2是素数,那么2的倍数一定是合数,3是素数,3的倍数也是合数。当知道某个数是素数之后,它的倍数就可以去掉了。这样后面要筛的数就会越来越少,比如2的倍数就可以去掉一半的数,三的倍数可以去掉1/3的数等等。


n=int(input())
v=[0 for i in range(n+1)] #初始化全为0
v[1]=1 
for i in range(2,n+1):
    if v[i]==0:        
        for j in range(2*i,n+1,i):            
            v[j]=1    #所有i的倍数标记为1
for i in range(2,n+1):
    if v[i]==0:
        print(i)

算法的时间复杂度为O(nlog(logn))
但是我们仍然可以发现,j是从2 * i开始计数的,实际上2 * i是2的倍数,在筛2的倍数的时候已经筛掉了,3 * i是3的倍数,在筛3的倍数的时候也已经筛掉了,所有小于i * i 的倍数其实都被筛掉了,因此j的起始值可以取 i * i。上述方法简称埃氏筛法。
把开平方法和上述程序结合起来的结果似乎和把2 * i改成i * i的结果等同。
(4)欧式筛法
对于一般的数据,埃氏筛法已经足够了,但是进一步优化,我们仍然能找到埃氏筛法的一些不足。
比如2已经把6筛掉了,3又筛了一次。也就是说素数的公倍数会被这些素数重复筛,这显然是不必要的。所以欧式筛法和埃氏筛法的区别就在于欧式筛法每个数只筛一次。
(5)Miller-Rabin算法和Pollard-Rho算法
除此之外,还有一些素数测试算法,在牺牲一小部分正确率来降低时间复杂度的方法,可以移步这篇文章

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,576评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,515评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,017评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,626评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,625评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,255评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,825评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,729评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,271评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,363评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,498评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,183评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,867评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,338评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,458评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,906评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,507评论 2 359