从一个素数问题到优化算法的重要性
做题有感
方法一:直接计算判断
数学优化算法:遍历范围的缩小以减小耗时
遍历全部
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int isPrime1 (int target) { int i; if (target <= 1 ){ printf ("error" ); return -1 ; } for (i = 2 ; i <= target; i++) { if (target % i == 0 ) return 0 ; } return 1 ; }
遍历至sqrt(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int isPrime2 (int target) { int i; if (target <= 1 ){ printf ("error" ); return -1 ; } for (i = 2 ; i <= (int )sqrt (target); i++) { if (target % i == 0 ) return 0 ; } return 1 ; }
继续分析,其实质数还有一个特点,除了 2 和 3,它总是等于 6x-1 或者 6x+1 ,其中 x 是大于等于1的自然数。
上面的结论证明如下: (1)6x 能被 6 整除; (2)6x+2 能被 2 整除; (3)6x+3 能被 3 整除; (4)6x+4 能被 2 整除。 那么,就只有 6x+1 和 6x+5 (即等同于6x-1) 可能是质数了。
又因为合数有个性质,合数肯定有一个小于或等于根号的质因数,所以如果 n 能被 6 倍数两侧的数(才有可能是质数)整除,那么 n 是合数,否则 n 是素数。所以循环的步长可以设为 6,然后每次只判断 6 两侧的数能否整除 n 即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int isPrime3 (int target) { int i; if (target <= 1 ){ printf ("error" ); return -1 ; } if (target % 6 !== 1 && target % 6 !==5 ) return 0 ; for (i = 5 ; i <= (int )sqrt (target); i += 6 ) { if (target % i == 0 && target % (i + 2 ) == 0 ) return 0 ; } return 1 ; }
方法二:查素数表
思路 : 如果一个数不能整除比它小的任何素数,那么这个数就是素数 这种“打印”素数表的方法效率很低,不推荐使用,可以学习思想
1 2 3 4 5 6 7 8 9 10 11 12 13 int isPrime (int target, int count, int * PrimeArray) { int i = 0 ; for (i = 0 ; i < count; i++) { if (target % PrimeArray[i] == 0 ) return 0 ; } return 1 ; }
方法三:筛法(得素数表) 普通筛法——埃拉托斯特尼(Eratosthenes)筛法 用百度百科对埃拉托斯特尼筛法简单描述:要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void Eratprime ( int * isprime, int upper_board ) { int i = 0 ; int j = 0 ; for (i = 2 ; i <= upper_board; i++) isprime[i] = 1 ; for (i = 2 ; i < (int )sqrt (upper_board); i++) { if (isprime[i]) { isprime[i] = 1 ; } for (j = 2 ; i * j <= upper_board; j++) { isprime[i * j] = 0 ; } } }
线性筛法——欧拉筛法
思路 : 我们再思考一下上面的埃拉托斯特尼筛法,会发现,在“剔除“非素数时,有些合数会重复赋值。这样就会增加复杂度,降低效率。
-> 用一个标识符避免重复筛选
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 void PrimeList (int * Prime, bool * isPrime, int n) { int i = 0 ; int j = 0 ; int count = 0 ; if (isPrime != NULL ) { for (i = 2 ; i <= N; i++) { isPrime[i] = true ; } } if (isPrime != NULL && Prime != NULL ) { for (i = 2 ; i <= N; i++) { if (isPrime[i]) Prime[count++] = i; for (j = 0 ; (j < count) && (Prime[j] * (long long )i) <= N; j++) { isPrime[i * Prime[j]] = false ; if (i % Prime[j] == 0 ) break ; } } } }
参考:https://github.com/hairrrrr/C-CrashCourse/blob/master/content/c-notes/你不知道的几种素数判断方法,由浅入深,详解.md )