几个常见算法整理

原文:http://blog.csdn.net/u011002533/article/details/62057426

1.gcd算法

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int gcd(int a, int b)    
  2. {    
  3.     return (a==0)?b:gcd(b%a, a);    
  4. }      
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //递推法  
  2. int gcd(int m, int n)    
  3. {    
  4.     while(m>0)    
  5.     {    
  6.         int c = n % m;    
  7.         n = m;    
  8.         m = c;    
  9.     }    
  10.     return n;    
  11. }    
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* 连续整数试探算法,计算最大公约数 */    
  2. int gcd(int m, int n)    
  3. {    
  4.     if(m>n) {    
  5.         int temp = m;    
  6.         m = n;    
  7.         n = temp;    
  8.     }    
  9.     int t = m;    
  10.     while(m%t || n%t)    
  11.     {     
  12.         t--;    
  13.     }    
  14.     return t;    
  15. }    

2.素数判断(该内容转载自http://blog.csdn.net/arvonzhang/article/details/8564836)

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //最笨做法  
  2. bool IsPrime(unsigned n)    
  3. {    
  4.     if (n<2)    
  5.     {       
  6.         //小于2的数即不是合数也不是素数    
  7.         throw 0;    
  8.     }    
  9.     for (unsigned i=2;i<n;++i)    
  10.     {     
  11.         //和比它小的所有的数相除,如果都除不尽,证明素数    
  12.         if (n%i==0)    
  13.         {    
  14.             //除尽了,则是合数    
  15.             return false;    
  16.         }    
  17.     }    
  18.     return true;    
  19. }    
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //一般做法  
  2.    num = 0;  
  3.     for(i=2; i<=n; i++)  
  4.     {  for(j=2; j<=sqrt(i); j++)  
  5.          if( j%i==0 ) break;  
  6.        if( j>sqrt(i) ) prime[num++] = i;    
  7.     }  

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //素数表做法  
  2. bool IsPrime2(unsigned n)    
  3. {    
  4.     if ( n < 2 )    
  5.     { // 小于2的数即不是合数也不是素数    
  6.         throw 0;    
  7.     }    
  8.     static unsigned aPrimeList[] = { // 素数表    
  9.         1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,    
  10.         43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 113,     
  11.         193, 241, 257, 337, 353, 401, 433, 449, 577, 593, 641,     
  12.         673, 769, 881, 929, 977, 1009, 1153, 1201, 1217, 1249,     
  13.         1297,1361, 1409, 1489, 1553, 1601, 1697, 1777, 1873,     
  14.         1889, 2017, 2081, 2113, 2129, 2161, 2273, 2417, 2593,     
  15.         2609, 2657, 2689, 2753, 2801, 2833, 2897, 3041, 3089,     
  16.         3121, 3137, 3169, 3217, 3313, 3329, 3361, 3457, 3617,     
  17.         3697, 3761, 3793, 3889, 4001, 4049, 4129, 4177, 4241,     
  18.         4273, 4289, 4337, 4481, 4513, 4561, 4657, 4673, 4721,     
  19.         4801, 4817, 4993, 5009, 5153, 5233, 5281, 5297, 5393,     
  20.         5441, 5521, 5569, 5857, 5953, 6113, 6257, 6337, 6353,     
  21.         6449, 6481, 6529, 6577, 6673, 6689, 6737, 6833, 6961,     
  22.         6977, 7057, 7121, 7297, 7393, 7457, 7489, 7537, 7649,     
  23.         7681, 7793, 7841, 7873, 7937, 8017, 8081, 8161, 8209,     
  24.         8273, 8353, 8369, 8513, 8609, 8641, 8689, 8737, 8753,     
  25.         8849, 8929, 9041, 9137, 9281, 9377, 9473, 9521, 9601,     
  26.         9649, 9697, 9857     
  27.     };    
  28.         
  29.     const int nListNum = sizeof(aPrimeList)/sizeof(unsigned);//计算素数表里元素的个数    
  30.     for (unsigned i=2;i<nListNum;++i )    
  31.     {     
  32.         if(n/2+1<aPrimeList[i])    
  33.         {    
  34.             return true;    
  35.         }    
  36.         if(0==n%aPrimeList[i])    
  37.         {    
  38.             return false;    
  39.         }    
  40.     }    
  41.     /*由于素数表中元素个数是有限的,那么对于用素数表判断不到的数,就只有用笨蛋办法了*/    
  42.     for (unsigned i=aPrimeList[nListNum-1];i<n/2+1;i++ )    
  43.     {     
  44.         if (0==n%i)    
  45.         {     
  46.             // 除尽了,合数     
  47.             return false;    
  48.         }    
  49.     }    
  50.     return true;     
  51. }    
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 费马小定理:对于两个互质的素数N和P,必有:N^(P-1)%P=1   
  2. 算法思路:  
  3. 对于N,从素数表中取出任意的素数对其进行费马测试,如果取了很多个素数,N仍未测试失败,那么则认为N是素数。当然,测试次数越多越准确,但一般来讲50次就足够了。  
  4. bool IsPrime3(unsigned n)    
  5. {    
  6.     if ( n < 2 )    
  7.     {     
  8.         // 小于2的数即不是合数也不是素数    
  9.         throw 0;    
  10.     }    
  11.     static unsigned aPrimeList[] = {    
  12.         2, 3, 5, 7, 11, 17, 19, 23, 29, 31, 41,    
  13.         43, 47, 53, 59, 67, 71, 73, 79, 83, 89, 97    
  14.     };    
  15.     const int nListNum = sizeof(aPrimeList) / sizeof(unsigned);    
  16.     for (int i=0;i<nListNum;++i)    
  17.     {     
  18.         // 按照素数表中的数对当前素数进行判断    
  19.         if (1!=Montgomery(aPrimeList[i],n-1,n)) // 蒙格马利算法    
  20.         {    
  21.             return false;    
  22.         }    
  23.     }    
  24.     return true;    
  25. }    
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 拉宾米勒测试算法---目前最快的判断素数算法  
  2. 拉宾米勒测试是一个不确定的算法,只能从概率意义上判定一个数可能是素数,但并不能确保。算法流程如下:  
  3.        1.选择T个随机数A,并且有A<N成立。  
  4.        2.找到R和M,使得N=2*R*M+1成立。  
  5.        快速得到R和M的方式:N用二进制数B来表示,令C=B-1。因为N为奇数(素数都是奇数),所以C的最低位为0,从C的最低位的0开始向高位统计,一直到遇到第一个1。这时0的个数即为R,M为B右移R位的值。  
  6.        3.如果A^M%N=1,则通过A对于N的测试,然后进行下一个A的测试  
  7.        4.如果A^M%N!=1,那么令i由0迭代至R,进行下面的测试  
  8.        5.如果A^((2^i)*M)%N=N-1则通过A对于N的测试,否则进行下一个i的测试   
  9.        6.如果i=r,且尚未通过测试,则此A对于N的测试失败,说明N为合数。  
  10.        7.进行下一个A对N的测试,直到测试完指定个数的A  
  11.        通过验证得知,当T为素数,并且A是平均分布的随机数,那么测试有效率为1 / ( 4 ^ T )。如果T > 8那么测试失误的机率就会小于10^(-5),这对于一般的应用是足够了。如果需要求的素数极大,或着要求更高的保障度,可以适当调高T的值。  
  12. bool RabbinMillerTest( unsigned n )    
  13. {    
  14.     if (n<2)    
  15.     {     
  16.          // 小于2的数即不是合数也不是素数    
  17.         throw 0;    
  18.     }    
  19.     const unsigned nPrimeListSize=sizeof(g_aPrimeList)/sizeof(unsigned);//求素数表元素个数    
  20.     for(int i=0;i<nPrimeListSize;++i)    
  21.     {    
  22.         // 按照素数表中的数对当前素数进行判断    
  23.         if (n/2+1<=g_aPrimeList[i])    
  24.         {    
  25.             // 如果已经小于当前素数表的数,则一定是素数    
  26.             return true;    
  27.         }    
  28.         if (0==n%g_aPrimeList[i])    
  29.         {    
  30.             // 余数为0则说明一定不是素数    
  31.             return false;    
  32.         }    
  33.     }    
  34.     // 找到r和m,使得n = 2^r * m + 1;    
  35.     int r = 0, m = n - 1; // ( n - 1 ) 一定是合数    
  36.     while ( 0 == ( m & 1 ) )    
  37.     {    
  38.         m >>= 1; // 右移一位    
  39.         r++; // 统计右移的次数    
  40.     }    
  41.     const unsigned nTestCnt = 8; // 表示进行测试的次数    
  42.     for ( unsigned i = 0; i < nTestCnt; ++i )    
  43.     {     
  44.         // 利用随机数进行测试,    
  45.         int a = g_aPrimeList[ rand() % nPrimeListSize ];    
  46.         if ( 1 != Montgomery( a, m, n ) )    
  47.         {    
  48.             int j = 0;    
  49.             int e = 1;    
  50.             for ( ; j < r; ++j )    
  51.             {    
  52.                 if ( n - 1 == Montgomery( a, m * e, n ) )     
  53.                 {    
  54.                     break;    
  55.                 }    
  56.                 e <<= 1;    
  57.             }    
  58.             if (j == r)    
  59.             {    
  60.                 return false;    
  61.             }    
  62.         }    
  63.     }    
  64.     return true;    
  65. }    
素数筛法

原理就是标记,防止重复判断。比如2是素数,所有是2的倍数都不是素数,然后标记上,接着判断3,执行到根下,这样就会得到一个素数表,所有没有被标记的都是素数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 素数筛法  
  2. 以下转载自http://blog.csdn.net/tongyongzh/article/details/6693409  
  3. #include <cstdlib>    
  4. #include <cmath>    
  5. using namespace std;    
  6. const int MAX=1000;    
  7.     
  8. int main()    
  9. {    
  10.      int i=0,j=0,n=sqrt(MAX)+1;    
  11.      int a[MAX+1]={0};    
  12.     
  13.      for(i=2;i<=n;i++)  //筛选循环    
  14.        for(j=2;j<=MAX/i;j++)    
  15.            a[j*i]=1;    
  16.     
  17.           
  18.      for(i=2;i<=MAX;i++)    
  19.         if(a[i]==0)    
  20.         {    
  21.           cout.width(7);    
  22.           cout<<i<<" ";    
  23.         }    
  24.      system("pause");    
  25.      return 0;    
  26.          
  27. }    

线性筛法

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:24px;">int a[MAX_N+1];    
  2. int p[MAX_N+1];    
  3. int nCount=0;    
  4.     
  5. void Init(int n) //线性筛法,不过在小范围上(约n<1e7)不比上一个方法快    
  6. {    
  7.     for (int i=2;i<=n;i++)    
  8.     {    
  9.         if (a[i]==0)    
  10.         {    
  11.             p[++nCount]=i;    
  12.         }    
  13.         for (int j=1,k; (j<=nCount) && (k=i*p[j])<=n; j++) //筛选循环    
  14.         {    
  15.             a[k] = 1 ;    
  16.             if (i%p[j] == 0) break;    
  17.         }    
  18.     }    
  19. }    
  20.     
  21. #include <iostream>    
  22. int main(void)    
  23. {    
  24.     Init(MAX_N);    
  25.     for(int n=1; p[n]>1; ++n)    
  26.     {    
  27.         printf("%5d", p[n]);    
  28.     }    
  29.     return 0;    
  30. }</span>  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值