素數序列的生成及其應用(采用了新學的更高效的算法:布爾標記法 + 倍數淘汰法)
阿新 • • 發佈:2018-04-19
lin ++ lse 大於 所有 void ont null -a
問題:
- 不超過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 34 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 /*釋放boolean_flag_array末尾可能存在的連續多個FALSE_FLAG*/ 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 piia = getBooleanFlagArrayFor(upper_limit); 82 COUNT i = 1, j = 1; 83 while (i < piia.count) { 84 if (piia.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
素數序列的生成及其應用(采用了新學的更高效的算法:布爾標記法 + 倍數淘汰法)