素数序列的生成及其应用(采用了新学的更高效的算法:布尔标记法 + 倍数淘汰法)

Posted yawenunion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了素数序列的生成及其应用(采用了新学的更高效的算法:布尔标记法 + 倍数淘汰法)相关的知识,希望对你有一定的参考价值。

问题:

  • 不超过2000的素数有哪些?
  • 她的QQ号是素数吗?

解决:

已知:

  1. 1不是素数
  2. 2是素数
  3. 大于2的偶数不是素数
  4. 大于2的素数是奇数
  5. 当自然数k > 1时,素数的k被数不是素数

策略:

  1. 采用大型布尔数组,其元素取值只有0(FALSE_FLAG)和1(TRUE_FLAG)两种
  2. 用大型布尔数组中下标为i的位置代表奇数(2*i + 1)
  3. 断定(2*i + 1)为素数当且仅当在大型布尔数组中下标为i的位置的元素的值为1(TRUE_FLAG)

编码:

头文件:prime_number.h

 1 #ifndef PRIME_NUMBER_H
 2 #define PRIME_NUMBER_H
 3 
 4 typedef enum{FALSE_FLAG, TRUE_FLAG} BOOLEAN_FLAG; // 当作布尔类型来用
 5 typedef unsigned long long COUNT, PRIME_INTEGER; // 制定素数数组的下标数据类型和元素数据类型
 6 
 7 typedef struct {
 8     BOOLEAN_FLAG *boolean_flag_array;
 9     COUNT count;
10 }BOOLEAN_FLAG_ARRAY; // 大型布尔数组
11 
12 /************************************全局常量的声明************************************/
13 
14 extern const 
15 BOOLEAN_FLAG_ARRAY EMPTY_BOOLEAN_FLAG_ARRAY; // 空BOOLEAN_FLAG_ARRAY
16 
17 extern const char 
18 *PRINT_FORMAT_STRING_OF_PRIME_INTEGER_TYPE, // 素数数组的元素的输出格式符
19 *PRINT_FORMAT_STRING_OF_COUNT_TYPE; // 素数数组的下标的输出格式符
20 
21 /**************************************方法的声明**************************************/
22 
23 /*获取upper_limit以内的素数的索引数组*/
24 BOOLEAN_FLAG_ARRAY getBooleanFlagArrayFor(PRIME_INTEGER upper_limit);
25 
26 /*格式化地打印upper_limit以内的全部素数*/
27 void printPrimeIntegerArrayBellow(PRIME_INTEGER upper_limit);
28 
29 /*判断一个给定的数是否为素数*/
30 BOOLEAN_FLAG isPrimeInteger(PRIME_INTEGER n);
31 
32 #endif

 

源文件:prime_number.c

  1 #include "prime_number.h"
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 
  5 /************************************全局常量的定义************************************/
  6 
  7 const BOOLEAN_FLAG_ARRAY 
  8 EMPTY_BOOLEAN_FLAG_ARRAY = { NULL, 0 }; // 空BOOLEAN_FLAG_ARRAY
  9 
 10 const char 
 11 *PRINT_FORMAT_STRING_OF_PRIME_INTEGER_TYPE = "%3llu", // 制定素数数组的元素的输出格式符
 12 *PRINT_FORMAT_STRING_OF_COUNT_TYPE = "%02llu"; // 制定素数数组的下标的输出格式符
 13 
 14 /**************************************方法的定义**************************************/
 15 
 16 /*获取upper_limit以内的素数的索引数组*/
 17 BOOLEAN_FLAG_ARRAY
 18 getBooleanFlagArrayFor(PRIME_INTEGER upper_limit) {
 19     /*不存在小于2的素数*/
 20     if (upper_limit < 2) {
 21         return EMPTY_BOOLEAN_FLAG_ARRAY;
 22     }
 23     /*
 24     **upper_limit以内至多有max_count个奇数,
 25     **且其中的第一个奇数(用下标为0的位置代表)是1,已知1不是素数,
 26     **于是相应地开辟含有max_count个位置的boolean_flag_array,
 27     **且boolean_flag_array的第一个位置仅起占位作用,
 28     **在1以后的奇数序列为3, 5, 7, 9, 11, 13 ...
 29     **依次用下标为1, 2, 3, 4, 5, 6 ...的位置来代表
 30     **这样的话,下标为i的位置代表的奇数就是(2*i + 1)
 31     **下标为i的位置的BOOLEAN_FLAG值就用来指示该位置代表的奇数是否为素数
 32     */
 33     COUNT max_count = (upper_limit + 1) / 2;
 34     BOOLEAN_FLAG *boolean_flag_array = (BOOLEAN_FLAG *)malloc(max_count * sizeof(BOOLEAN_FLAG));
 35     COUNT i = 1, j;
 36     while (i < max_count) {
 37         /*先把第一个位置以后的所有位置标记为TRUE_FLAG*/
 38         boolean_flag_array[i++] = TRUE_FLAG;
 39     }
 40     for (i = 1; i < max_count; ++i) {
 41         if (boolean_flag_array[i] == FALSE_FLAG) {
 42             continue; // 它的最小质因数的倍数都已经被划掉了
 43         }
 44         for (j = i; (j += 2 * i + 1) < max_count; ) {
 45             /*(k>1), 素数的k倍数必然是合数,就标记为FALSE_FLAG*/
 46             boolean_flag_array[j] = FALSE_FLAG;
 47         }
 48     }
 49 
 50     /*在下一个修订版Version 2.2中做了改动:释放boolean_flag_array末尾可能存在的连续多个FALSE_FLAG。当前版本为2.0,暂且不应用此改动。*/
 51     /*for (i = max_count; boolean_flag_array[--i] == FALSE_FLAG;);
 52     boolean_flag_array = (BOOLEAN_FLAG *)realloc(boolean_flag_array, (i + 1) * sizeof(BOOLEAN_FLAG));*/
 53     
 54     return (BOOLEAN_FLAG_ARRAY) { boolean_flag_array, max_count };
 55 }
 56 
 57 /*以“PrimeIntegerArray(index) = prime_integer”并换行的格式打印素数元素*/
 58 void 
 59 printPrimeIntegerElement(COUNT index, PRIME_INTEGER prime_integer) {
 60     printf("PrimeIntegerArray(");
 61     printf(PRINT_FORMAT_STRING_OF_COUNT_TYPE, index);
 62     printf(") = ");
 63     printf(PRINT_FORMAT_STRING_OF_PRIME_INTEGER_TYPE, prime_integer);
 64     printf("\\n");
 65 }
 66 
 67 /*格式化地打印upper_limit以内的全部素数*/
 68 void
 69 printPrimeIntegerArrayBellow(PRIME_INTEGER upper_limit) {
 70     /**/
 71     if (upper_limit < 2) {
 72         printf("EMPTY_BOOLEAN_FLAG_ARRAY\\n");
 73         return;
 74     }
 75     /*至少有一个*/
 76     printPrimeIntegerElement(0, 2);
 77     if (upper_limit == 2) {
 78         return;
 79     }
 80     /*有好多个呢*/
 81     BOOLEAN_FLAG_ARRAY bfa = getBooleanFlagArrayFor(upper_limit);
 82     COUNT i = 1, j = 1;
 83     while (i < bfa.count) {
 84         if (bfa.boolean_flag_array[i] == TRUE_FLAG) {
 85             /*这里的i是boolean_flag_array数组下标,它的特性如下:
 86             **(1)在boolean_flag_array数组中下标为i的位置代表的奇数就是(2*i + 1)
 87             **(2)断定(2*i + 1)为素数当且仅当在boolean_flag_array数组中下标为i的位置的BOOLEAN_FLAG为TRUE_FLAG
 88 
 89             **而这里的j是要输出的素数数组的下标
 90             **只有确实输出了一个素数,j才加1
 91             */
 92             printPrimeIntegerElement(j++, 2 * i + 1);
 93         }
 94         ++i;
 95     }
 96 }
 97 
 98 /*判断一个给定的数是否为素数*/
 99 BOOLEAN_FLAG
100 isPrimeInteger(PRIME_INTEGER n) {
101     /*已知2是素数*/
102     if (n == 2) {
103         return TRUE_FLAG;
104     }
105     /*小于2的数以及大于2的偶数都不是素数*/
106     if (n < 2 || n % 2 == 0) {
107         return FALSE_FLAG;
108     }
109     /*
110     **大于2的奇数在boolean_flag_array中对应的位置的下标为(n - 1) / 2
111     **该位置的BOOLEAN_FLAG值就指示着对应的奇数是否确实为素数
112     */
113     return getBooleanFlagArrayFor(n).boolean_flag_array[(n - 1) / 2];
114 }

 

 

源文件:main.c

 1 #include "prime_number.h"
 2 
 3 #include <stdio.h>
 4 
 5 int main(int argc, char **argv) {
 6 
 7     printPrimeIntegerArrayBellow(200);
 8     printf("isPrimeInteger(65537) = %s\\n", isPrimeInteger(65537)?"Yes":"No");
 9 
10     return 0;
11 }

 

运行:

Microsoft Visual Studio Enterprise 2017 version 15.6.6 on Windows 10 Pro 1709

GCC version 7.3.1 on Manjaro Linux

 

以上是关于素数序列的生成及其应用(采用了新学的更高效的算法:布尔标记法 + 倍数淘汰法)的主要内容,如果未能解决你的问题,请参考以下文章

素数序列的生成及其应用 Advanced Version 1

快速排序算法及其思想的应用(寻找一个序列中第k小元素)

关于Eratosthenes筛子算法筛选小于n的素数的理解

具有素数列表的高效素数分解算法

希尔排序的具体实现及其原理

大素数高效算法判断