• [原]素数判定


    大学生程序代写
    路漫漫其修远兮,吾将上下而求索!

    素数判定算法

    1. 素数判定问题

    素数判定问题是一个非常常见的问题,本文介绍了常用的几种判定方法。

    2. 原始算法

    素数的定义是,除了能被1和它本身整除而不能被其他任何数整除的数。根据素数定义 只需要用2到n-1去除n,如果都除不尽,则n是素数,否则,只要其中有一个数能整除则n不是素数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    bool is_primer1(int num) {
      
      int i;
      
      for(i = 2; i < num; i++) {
      
        if(num % i == 0) {
      
          return true;
      
        }
      
      }
      
      return false;
      
    }

    3. 改进算法

    n不是素数,则n可表示为a*b,其中2<=a<=b<=n-1,则a,b中必有一个数满足:1<x<=sqrt(n),因而,只需要用2~sqrt(n)去除n,这样就得到一个复杂度为O(sqrt(n))的算法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    bool is_primer2(int num) {
      
      int i;
      
      int upper = sqrt(num);
      
      printf("primer2:%d ", upper);
      
      for(i = 2; i <= upper; i++) {
      
        if(num % i == 0) {
      
          return true;
      
        }
      
      }
      
      return false;
      
    }

    4. 筛选算法

    更高效地素数判断方法应该是将素数预先保存到一个素数表中,当判断一个数是否为素数时,直接查表即可。这种方法需要解决两个问题:

    (1) 怎样快速得到素数表?(采用筛选方法)

    (2) 怎样减少素数表的大小?(采用位图数据结构)

    对于1到n全部整数,逐个判断它们是否是素数,找出一个非素数,就把它挖掉,最后剩下的就是素数。具体方法是:

    <1> 定义is_primer[i] = true;

    <2> 从2开始,依次遍历整个is_primer(直到sqrt(N)),如果is_primer[i]=true,则is_primer[n*i]=false

    如1,2,3,4,5,6,7,8,9,10,则

    从2开始遍历:

    is_primer[2]=true,则is_primer[4]= is_primer[6]= is_primer[8]= is_primer[10]= true

    is_primer[3]=true,则is_primer[6]= is_primer[9]= true

    为了减少内存使用率,算法使用了位图数据结构,关于位图,可参考:http://dongxicheng.org/structure/bitmap/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    bool load_primer_table1() { //保存素数表
      
      int i;
      
      for(i = 1; i < INT_MAX; i++) {
      
        if(i % 2 != 0 //偶数一定不是素数
      
          && is_primer2(i)) {
      
          set(i);
      
        }
      
      }
      
    }
      
    bool load_primer_table2() {//另一种更快的方法保存素数表
      
      int i, j;
      
      for(i = 1; i <= INT_MAX; i++) {
      
        if( i % 2) {
      
          set(i);
      
        } else {
      
          clear(i);
      
        }
      
      }
      
      int upper = sqrt(INT_MAX);
      
      for(i = 1; i <= upper; i++) {
      
        if(test(i)) {
      
          for(j = i + i; j < INT_MAX; j += i)
      
            set(i);
      
        }
      
      }
      
    }
      
    bool is_primer3(long num) { //查表判断是否为素数
      
      if(test(num))
      
        return true;
      
      return false;
      
    }

    5. 优化的筛选算法

    (1) 存储方式优化

    仍然采用位图方式存储,只不过是位图中只存储奇数,这样一下子节省了一半空间(需要的空间仅为4G/(32*2)=64MB)

    存储空间优化后,算法效率也会提升很多,如:1,2,…,30

    只需存储3,5,7,9,11,13,15,17,19,21,23,25,27,29

    i=0, is_primer[0] =true, 把下标[3][6][9][12],即9,15,21,27,标为false

    i=1, s_primer[0] =true,把下标为[6][11],即15,25标为false

    i=2, 2*i+3>sqrt(30),结束

    即:i=s, 把下标为s(2*t+1)+3t,其中,t=1,2,3,…中所有的的is_primer置为false

    (2) 优化删选算法

    a是素数,则下一个起点是a*a,把后面的所有的a*a+2*i*a筛掉。即欲求n以内的素数,就先把sqrt(n)内的素数求出来,用已经求得的素数来筛出后面的合数。

    6. 总结

    至今为止,没有任何人发现素数的分布规律,也没有人能用一个公式计算出所有的素数。关于素数的很多的有趣的性质或者科学家的努力,如:

    (1) 高斯猜测,n以内的素数个数大约与n/ln(n)相当,或者说,当n很大时,两者数量级相同。这就是著名的素数定理。

    (2) 十七世纪费马猜测,2的2^n次方+1,n=0,1,2…时是素数,这样的数叫费马素数,可惜当n=5时,2^32+1就不是素数,至今也没有找到第六个费马素数。

    (3) 18世纪发现的最大素数是2^31-1,19世纪发现的最大素数是2^127-1,20世纪末人类已知的最大素数是2^859433-1,用十进制表示,这是一个258715位的数字。

    (4) 孪生素数猜想:差为2的素数有无穷多对。目前知道的最大的孪生素数是1159142985×2^2304-1和1159142985×2^2304+1。

    (5) 歌德巴赫猜想:大于2的所有偶数均是两个素数的和,大于5的所有奇数均是三个素数之和。其中第二个猜想是第一个的自然推论,因此歌德巴赫猜想又被称为1+1问题。我国数学家陈景润证明了1+2,即所有大于2的偶数都是一个素数和只有两个素数因数的合数的和。国际上称为陈氏定理。(摘自《http://chuanbindeng.blog.163.com/blog/static/67886226200982892139468/》)

    7. 参考资料

    http://www.doc88.com/p-5780302974.html

    http://chuanbindeng.blog.163.com/blog/static/67886226200982892139468/

    作者:chao1983210400 发表于2013-7-25 19:33:55 原文链接
    阅读:10 评论:0 查看评论
  • 相关阅读:
    sqlserver中判断表或临时表是否存在
    Delphi 简单方法搜索定位TreeView项
    hdu 2010 水仙花数
    hdu 1061 Rightmost Digit
    hdu 2041 超级楼梯
    hdu 2012 素数判定
    hdu 1425 sort
    hdu 1071 The area
    hdu 1005 Number Sequence
    hdu 1021 Fibonacci Again
  • 原文地址:https://www.cnblogs.com/java20130726/p/3218702.html
Copyright © 2020-2023  润新知