四种质数筛选算法总结(c++) |
您所在的位置:网站首页 › 秦国几代君王作为 › 四种质数筛选算法总结(c++) |
文章目录
质数筛选枚举法埃氏筛线氏筛奇数筛
参考自:
leetcode题解,计数质数
质数筛选
质数:除了1和它本身以外不再有其他因数的自然数。 合数:与质数相反。 枚举法枚举法是查找质数最容易想到的方法,又被称为试除法。 它的思路就是遍历从2到n这个数的所有的数字,判断这个数字能否被这个序列种的任意一个序列整除,如果整除,则说明它不具有唯一的因子(1和它本身) 代码如下: int func(int n) { int ans = 0; bool isPrimer; for (int i = 2; i if (i % j == 0) { //如果有任意一个数能够被整除,则说明其一定不是质数,则直接退出 isPrimer = false; break; } } if (isPrimer) //如果是质数,则递增 { ans++; } } return ans; }枚举优化 观察以下数字的形式: 4: 1 * 4 ,2 * 2 , 4 * 1 5: 1* 5 ,sqrt(5) * sqrt(5) , 5 * 1 6: 1* 6 ,2 * 3 ,sqrt(6) * sqrt(6) ,3 * 2 , 6 * 1 8: 1* 6 ,2 * 4 ,sqrt(8) * sqrt(8) ,4 * 2 , 6 * 1 可以得到,无论数字是质数还是合数,可以认为以中间的两个因子相乘,他们的左右两边是一致的。也就是说,遍历了前面,我们如果继续遍历,则会导致重复的现象出现,则我们完全可以避免他。 优化一个地方: ... for (int j=2;j if (isPrimer[i] == 1) { ans++; if ((long long) i*i isPrimer[j] = 0; } } } } return ans; } 线氏筛在埃氏筛中,我们存储重复标记元素的情况,我们无法避免它,但是我们利用线氏筛来完全避免这种情况。 根据《算术基本定理》: 算术基本定理: 任何一个大于1的 自然数 N,如果N不为 质数 ,那么N可以 唯一 分解成有限个质数的乘积. 例如: 16是一个合数,16可以 分解为 2 * 2 * 2 *2 是一个唯一的,有限个的质数乘积。 20 是一个合数,20 可以分解为 2 * 2 * 5 也是一个唯一的,有限个的质数的乘积。 因此得到结论: 有限多个质数的乘积 一定是一个合数 ---->质数 * 质数 * 质数 … = 合数 作为因子的每个质数不同,则最终的合数也不同。 临时存储每一个质数,只要后面的数字能够被这些质数整除,则直接结束循环,原因: 当前数 能被 质数数组中的某质数 整除,当前数一定是包含 该质数 的合数 合数拆分时,因子中,会出现 两个相同质数,不能保证合数不同 质数数组中后面质数都比 该质数 大。该质数 * >它的质数 = 合数后面一定会遇到 图例: 首先看数字2,它是质数,然后把这个数字放在质数数组[ 0 ]中,在确保范围的情况下,然后把2 依次乘以质数数组中每一项,得到的数字一定是合数(质数 * 质数 = 合数),由此,得到 4是合数,则标记为非质数 0。再来看数字3,它是质数,放入质数数组 [ 1 ]中,在确保范围的情况下,把3依次乘以质数数组中的每一项,得到6 和 9 因此,这两个数字也一定是合数,标识为 0。再来看数字4,它是合数,因此不用放入质数数组中,在确保范围的情况下,用4乘以质数数组中的每一项,得到 8 ( 4 * 2),你是否以为还是有数字12? 答案是并没有,因为,数字4能被质数数组中的第一项(2)整除,我的理解: 12可以被拆分为 2 * 2 * 3,2和3都在质数数组中出现了,因此就没有必要再利用3 * 4得到 12了,因为4可以由 2 * 2得到,因此直接结束此次循环。数字5,确定 10 和 15 不是质数 …优化后的埃氏筛: 偶数一定不是质数! 因此只遍历每一个奇数就可以奇数 * 偶数 = 偶数,因此不必讨论这种情况。奇数 * 奇数 =奇数,因此只在奇数范围内寻找。 class Solution { public: int countPrimes(int n) { //默认全部为true vector primer(n,1); int res=(n>2)?1:0; int t=0; for (int i=3;i res++; if ((long long)i*i primer[t]=0; } } } } return res; } }; |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |