求解1-n之间的素数

转自:http://blog.csdn.net/left_la/article/details/8807040


1、简陋的算法:

[cpp]  view plain copy
  1. void prime(int n)  
  2. {  
  3.     for (int i = 2; i < n; ++i)  
  4.     {  
  5.         int j;  
  6.         for (j = 2; j <= sqrt(i); ++j)  // 如果i不能被2到sqrt(i)之间的所有整数所整除,则其为素数   
  7.         {  
  8.             if (i%j==0) break;  
  9.         }  
  10.         if (j>sqrt(i))   
  11.             cout<<i<<" ";  
  12.     }  
  13.     cout<<endl;  
  14. }  
时间复杂度为O(n*sqrt(n))(注意在这里在分析算法时间复杂度的时候一定是o(n*sqrt(n)))

2.一位博友的解法(http://blog.csdn.net/sgbfblog/article/details/7860064

    最基本的想法就是对1到N得每个数进行判断,如果是素数则输出。一种改进的方法是不需要对1到N所有的数都进行判断,因为偶数肯定不是素数,而奇数可能是素数,可能不是。2,3,5都是素数,这可以直接得到。然后我们可以跳过2与3的倍数,即对于6n,6n+1, 6n+2, 6n+3, 6n+4, 6n+5, 我们只需要判断6n+1与6n+5是否是素数即可。
    判断某个数m是否是素数,最基本的方法就是对2到m-1之间的数整除m,如果有一个数能够整除m,则m就不是素数。判断m是否是素数还可以进一步改进,不需要对2到m-1之间的数全部整除m,只需要对 2到根号m之间的素数整除m就可以。如用2,3,4,5...根号m整除m。其实这还是有浪费,因为如果2不能整除,则2的倍数也不能整除,同理3不能整除则3的倍数也不能整除,因此可以只用 2到根号m之间小于根号m的素数去除即可。( 据我(lsj)了解,任何一个大于2的自然数都可以写成几个质数相乘的形式,不知道对不对
     给出一个最基本的解法就是预先可得2,3,5为素数,然后跳过2与3的倍数,从7开始,然后判断11,然后判断13,再是17...规律就是从5加2,然后加4,然后加2,然后再加4。如此反复即可,如下图所示,只需要判断7,11,13,17,19,23,25,29...这些数字。对这些数进行判断,如果是素数则输出。

     判断是否是素数采用改进后的方案,即对2到根号m之间的数整除m来进行判断。需要注意一点,不能直接用根号m判断,因为对于某些数字,比如121,开根号后得到的不一定是11,可能是10.999999,所以最好使用乘法判断,如代码中所示:

后来,我想了想,为什么这位博友能这么做。我们知道这样一个结论,素数只可能是6n-1或者6n+1,(这位博友证明了一下http://blog.csdn.net/code_pang/article/details/7880245)。我们选择5开始判断(因为5 = 6*1-1),根据上面这个结论,我们只需需要判断6n-1和6n+1, 5 = 6*1 - 1,那么接下来我们就应该判断6*1 + 1 =7 ,再下来是 6 * 2 - 1 = 11 = 7 + 4 = 5 +6。。。。。意会一下就明白了。按照这位博友的意思就是先加2,再加4。这位博友这种思想是对的,小小的思考了下。

  1. #include  <stdio.h>  
  2.   
  3. #define   MAXSIZE    100  
  4. #define   YES          1  
  5. #define   NO           0  
  6.   
  7. int main(void)  
  8. {  
  9.      int  prime[MAXSIZE];     /* array to contains primes */  
  10.      int  gap = 2;            /* increasing gap = 2 and 4 */  
  11.      int  count = 3;          /* no. of primes            */  
  12.      int  may_be_prime = 5;   /* working  variable        */  
  13.      int  i, is_prime;  
  14.   
  15.      prime[0] = 2;            /* Note that 2, 3 and 5 are */  
  16.      prime[1] = 3;            /* primes.                  */  
  17.      prime[2] = 5;  
  18.      while (count < MAXSIZE)  { /* loop until prime[] full*/  
  19.           may_be_prime += gap;  /* get next number        */  
  20.           gap           = 6 - gap; /* switch to next gap  */  
  21.           is_prime      = YES;  /* suppose it were a prime*/  
  22.           for (i = 2; prime[i]*prime[i] <= may_be_prime && is_prime; i++)  
  23.                if (may_be_prime % prime[i] == 0) /* NO    */  
  24.                     is_prime = NO; /* exit                */  
  25.           if (is_prime)       /* if it IS a prime...      */  
  26.                prime[count++] = may_be_prime;  /* save it */  
  27.      }  
  28.   
  29.      printf("\nPrime Number Generation Program");  
  30.      printf("\n===============================\n");  
  31.      printf("\nFirst %d Prime Numbers are :\n", count);  
  32.      for (i = 0; i < count; i++) {  
  33.           if (i % 10 == 0) printf("\n");  
  34.           printf("%5d", prime[i]);  
  35.      }  
  36.      return 0;  
  37. }  


3、埃拉托斯特尼筛法:

   给出要筛数值的范围n,找出\sqrt{n}以内的素数p_{1},p_{2},\dots,p_{k}。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个质数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个质数5筛,把5留下,把5的倍数剔除掉;不断重复下去......。


[cpp]  view plain copy
  1. void primeFilte(int n)  
  2. {  
  3.     bool *filter = new bool[n+1];  
  4.     for (int i=2; i<=n; i++)  
  5.         filter[i] = true;  
  6.   
  7.     for (int i=2; i<=sqrt(n); i++)  //注意我们这里只需要筛选到sqrt(n)
  8.     {  
  9.         if (filter[i])  
  10.         {  
  11.             int j = i*2;  
  12.             while (j<=n)  
  13.             {  
  14.                 if (filter[j])  
  15.                     filter[j] = false;  
  16.                 j+=i;  
  17.             }  
  18.         }  
  19.     }  
  20.   
  21.     for (int i=2; i<=n; i++)  
  22.         if (filter[i]) cout<<i<<" ";  
  23.     cout<<endl;  
  24.   
  25.     delete []filter;  
  26. }  
         时间复杂度为O(n*loglogn),已经是线性时间了。

     个人觉得,前面代码在给filter[i]赋值的时候就可以把偶数直接踢掉,这样我们后面直接从3开始踢就好了。

#include <iostream>
#include <cmath>
using namespace std;

void primeFilte(int n)  
{  
	bool *filter = new bool[n+1];  
	for (int i=2; i<=n; i++) {
		if(i & 0x1 || i==2) filter[i] = true;
		else filter[i] = false;
	}

	for (int i=3; i<=(int)sqrt((long double)n); i++)  
	{  
		if (filter[i])  
		{  
			int j = i*2;  
			while (j<=n)  
			{  
				if (filter[j])  
					filter[j] = false;  
				j+=i;  
			}  
		}  
	}  

	for (int i=2; i<=n; i++)  
		if (filter[i]) cout<<i<<" ";  
	cout<<endl;  

	delete []filter;  
} 

int main()
{
	primeFilte(100);
	system("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值