【C语言】求解素数(质数)的N种境界

前言:

   众所周知,不管是在学习、考试还是以后找工作中,对于求解素数的问题随处可见,而且还是一个重难点,为何要说是重难点呢?主要是因为对于不同的人往往会有不同做法,但大多数掌握的都是一些非常平庸的做法,完全没有技术含量。然而这对于我们这些技术人员无疑是一个BIG BUG。所以小编在此整理了一些求解套路,如有疑问,欢迎来扰。  

★试除法

   首先要介绍的,当然非"试除法"莫属啦。考虑到有些读者没听过,小编在此稍微解释一下:

"试除",顾名思义,就是不断地尝试能否整除。比如要判断自然数 x 是否质数,就不断尝试小于 x 且大于1的自然数,只要有一个能整除,则 x 是合数;否则,x 是素数。
  显然,试除法是最容易想到的思路。不客气地说,也是最平庸的思路。不过呢,这个最平庸的思路,也有好多种境界。不信请看下文:

境界1//假设要判断 x 是否为质数,就从 2 一直尝试到 x-1。这种做法,其效率应该是最差的

#include<stdio.h>
#include<Windows.h>
int main()
{
   int i = 0,k = 0;
   int count = 0;
   for(i=100; i<=200; i++)
  {
     for(k=2; k<i; k++)
    {
       if(i%k == 0)
       break;
    }
     if(k == i)
     printf("%d是素数\n",i);
     count++;
   }
   printf("\n%4d",count);
   system("pause");
   return 0;}

境界2//所有素数都是偶数,因此可以加快步长

#include<stdio.h>
#include<Windows.h>
int main()
{
   int i = 0, k = 0;
   int count = 0;
   for(i=101; i<=200; i+=2)
  {
     for(k=2; k<i; k++)
    {
        if(i%k == 0)
        break;
    }
     if(k==i)
     printf("%d是素数\n",i);
     count++;
  }
   printf("\n%4d",count);
   system("pause");
   return 0;
}     

境界3//除了2以外,所有可能的质因数都是奇数。所以,他们就先尝试 2,然后再尝试从 3 开始一直到 x/2 的所有奇数

#include<stdio.h>
#include<Windows.h>
int main()
{
   int i = 0, k = 0;
   int count = 0;
   for(i=100; i<=200; i+=2)
  {
     for(k=2;k<i/2;k++)   
    {
        if(i%k == 0)
        break;
    }
     if(k==i)
     printf("%d是素数\n",i);
     count++;
  }
   printf("\n%4d",count);
   system("pause");
   return 0;
}     

境界4//其实只要从 2 一直尝试到√简单解释一下:如,100的因数有:1和100,2和50,4和25,5和20,10和10

#include <stdio.h>
#include <math.h>
int main()
{
   int i = 0;
   int count = 0;
   for(i=100; i<=200; i++)
  {
     int j = 0;
     for(j=2; j<=sqrt(i); j++)
    {
        if(i%j == 0)
        break;
    }
     if(j>sqrt(i))
    {
     printf("%d ", i);
     count++;
    }
  }
   printf("\ncount = %d\n", count);
   return 0;
}

境界5//对于任意一个素数n,如果它有两个质因子x,y,显然n = x*y, 所以,由不等式性质可得,x <= sqrt(n), 即 x <= n^(1/2)。

#include <stdio.h>
#include <math.h>
int main()
{
    int i = 0;
    int count = 0;
    for(i=101; i<=200; i+=2)
   {
      int j = 0;
      for(j=2; j<=sqrt(i); j++)
     {
            if(i%j == 0)
               break;
     }
     if(j>sqrt(i))
     {
           count++;
           printf("%d ", i);
     }
   }
   printf("\ncount = %d\n", count);
   return 0;
}

★筛选法

  不知道的小伙伴请戳━>筛选法筛选法 ,真的是一个既巧妙又快速的求质数方法。其发明人是公元前250年左右的一位希腊大牛——埃拉托斯特尼。为什么说他是大牛捏?因为他本人精通多个学科和领域,至少包括:数学、天文学、地理学(地理学这个词汇,就是他创立的)、历史学、文学(他是一个诗人)。真的堪称"跨领域的大牛"。估计很多人把筛法仅仅看成是一种具体的方法。其实,筛法还是一种很普通的思想。在处理很多复杂问题的时候,都可以看到筛法的影子。那么,筛法如何求质数捏,说起来很简单:

先解释一下筛选法的步骤:

<1> 先将1挖掉(因为1不是素数)。
<2> 用2去除它后面的各个数,把能被2整除的数挖掉,即把2的倍数挖掉。
<3> 用3去除它后面的各数,把3的倍数挖掉。
<4> 分别用5…各数作为除数去除这些数以后的各数。

上述操作需要一个很大的容器去装载所有数的集合,只要满足上述条件,即2的倍数大于1的全部置0,3的倍数大于1的全部置0,4的倍数大于1的全部置0.。。。一直到这个数据集合的末尾,这样一来不为0的数就是素数了,然后按下标在里面进行查找就好了 

光说不练假把式,贴出代码:

#include<stdio.h>
int main()
{
int i,j,a[100],e;
for(i=0;i<100;i++)
   a[i]=i+1;
for(i=0;i<100;i++)
	{
	j=i-1;
	while(j>1)
	{
	e=a[i]%j;
	if(e==0)a[i]=0;
	j=j-1;
	}
}
for(j=1;j<100;j++)
	{
		if(a[j]!=0)
		{
			printf("%2d ",a[j]);
		}
}
return 0;
}

 ●确定质数的分布范围

估计素数个数求解公式x/ln(x)(素数定理)误差小于15%范围越大,误差越小

 ●存储容器

境界1构造整形容器

100~200所有素数,除去所有合数剩下的就是素数

思想:筛去2,3,5,7,11,13的倍数,剩下的就是素数

境界2布尔型容器

境界3按位(bit)存储

小编目前还是菜鸟级别,如有不正之处,欢迎批评指正!

猜你喜欢

转载自blog.csdn.net/qq_41035588/article/details/79726774