问题:
- 不超过2000的素数有哪些?
- 她的QQ号是素数吗?
解决:
已知:
- 1不是素数
- 2是素数
- 大于2的偶数不是素数
- 大于2的素数是奇数
- 当自然数k > 1时,素数的k被数不是素数
策略:
- 采用大型布尔数组,其元素取值只有0(FALSE_FLAG)和1(TRUE_FLAG)两种
- 用大型布尔数组中下标为i的位置代表奇数(2*i + 1)
- 断定(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(" "); 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 "); 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 ", 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