线性筛选法求素数

普通求法:

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

这个缺点就是如果n稍微大点运行的时间就很大

在普通的基础上改进方法(sqrt(n)):

#include<stdio.h>
#include<math.h>
int main()
{
    int i, n, x;
    while (scanf("%d", &n) == 1)
    {
         x= (int)sqrt(n);
         for (i = 2;i <=x;i++)
             if (n % i == 0)
                  break;
         if (i > x)
             printf("Yes\n");
         else
             printf("NO\n");
    }
    return 0;
}

用的sqrt,效率提高了,但是还是不够理想

于是我们有线性筛法(欧拉筛法):

原理:素数的倍数一定不是素数。

我们可以用一个长度为n+1的数组来存储信息(这种用另一个数组来保存信息的方法很常见也很有用),首先将所有的数字全初始化为0(素数),再将数字1与第一个素数2标记为1(非素数)从素数2开始将所有小于n的2的倍数都标记为1;继续该过程,将素数3的倍数筛掉,到循环结束时,标记仍为0的数就是素数。

//primer用来保存得到的素数

memset(check , 0 , sizeof(check) );

check[1] = 1;

int sum = 0,i,j;

for(i = 2;i <= n; i++)

{

       if(!check[i])

              primer[sum++]
= i;

       for(j
= i+1;j <= n;j += i)

              check[i]
= 1;

}

在这里插入图片描述

仔细分析这个算法的优化已经很好了,但是有些数字被重复使用了

于是乎真正的欧拉筛选来了

欧拉筛选保证一个合数只会被他最小的质数因子筛序一次

代码如下



check[1] = 1;
int sum =0, i, j;
for (i =
2;i <= n;i++)
{
    if (!check[i])
         primer[sum++]= i;
    for (j = 0;j <sum;j++)
    {
         if (i * primer[j] >n)
             break;
         check[i* primer[j]] = 1;
         if (i % primer[j] ==0)
             break;
    }
}

在这里插入图片描述
在这里插入图片描述
思路:

1.用线性筛法求出N范围内的素数保存在primer中(友情提示:大数组最好放在main函数之外定义,其他的题最好也是这样。为什么?百度“栈帧”,你就知道)
2.对这M组数据,用二分查找对比primer。



#include <stdio.h>

int n,w, primer[1000010],tot,s,i;

int check[100000010];

int main()

{

   
scanf("%d%d",&n,&w);

   
for(i = 2; i <= n; i++)

    {

       
if(check[i] == 0) primer[++tot] = i;

       
for(int j = 1; (j <= tot) && (i*primer[j] <= n); j++)

       
{

           
check[i * primer[j]] = 1;

           
if(i % primer[j] == 0) break;

       
}

    }

   
while(w--)

    {

       
scanf("%d",&s);

       
i = 1;

       
int j = tot, mid;

       
while(i <= j)

       
{

           
mid = (i + j) / 2;

           
if(s == primer[mid])

           
{

                printf("Yes\n");

                break;

           
}

           
else if(s < primer[mid]) j = mid - 1;

           
else i = mid + 1;

       
}

       
if(s != primer[mid]) printf("No\n");

    }

   
return 0;

}

参考资料

发布了17 篇原创文章 · 获赞 1 · 访问量 475

猜你喜欢

转载自blog.csdn.net/qq_43430261/article/details/89218665