素数筛法的复杂度
2012-12-06 00:28
197 查看
素数筛法的复杂度
Xie Xie给我看了一个链接性能调优--永远超乎想象,里面提到了素数筛法的复杂度,作者用实验发现此筛法是线形的。所谓素数筛法就是那个求小于n的所有素数最简单的算法:
bool* prime(int n) { bool *p = new bool ; memset(p, 0, sizeof p); for (int i = 2; i < n; i++) if (!p[i]) for (int j = 2*i; j < n; j+=i) p[j] = true; return p; }
此算法复杂度实际为 O(∑p<nn/p)=O(nloglogn) 。在可以测试的范围内,的确是接近线形的,虽然实际上不是。下面是如何估计 ∑1p :
loglog∞===<=ln(∑n=1∞1n)=ln⎛⎝∏p11−p−1⎞⎠=∑pln(11−p−1)=∑p−ln(1−p−1)∑p(1p+12p2+13p3+⋯)=⎛⎝∑p1p⎞⎠+∑p1p2(12+13p+14p2+⋯)∑p(1p+12p2+13p3+⋯)=⎛⎝∑p1p⎞⎠+∑p1p2(12+13p+14p2+⋯)⎛⎝∑p1p⎞⎠+∑p1p2(1+1p+1p2+⋯)=⎛⎝∑p1p⎞⎠+⎛⎝∑p1p(p−1)⎞⎠⎛⎝∑p1p⎞⎠+C(1)(2)(3)(4)(5)
更精确的,
∑p<n1p=loglogn+Θ(1)
注意此估计可直接得出素数有无穷多个
。
但是纯O(n)的算法也不是没有,只不过需要增加辅助空间保存质数列表:
bool* prime(int n) { bool *isp = new bool ; bool *p = new p(int(2*n/log(n)+20)); memset(isp, 0, sizeof isp); memset(p, 0, sizeof p); int np = 0; for (int i = 2; i < n; i++) { if (~isp(i)) p(np++) = i; for (int j = 0; j < pn && p[j]*i < n; j++) { isp[p[j]*i] = 1; if(i%p[j] == 0) break; } } delete p; return isp; }
这个算法的关键在于 if(i%pr[j] == 0) break;。它使得任何一个合数,只被它最小的质因数标记过一次。所以整个算法是线性的。但考虑到log(log(100000000))还不到3,故这个线性算法其实也只有理论上的价值罢了。
ps:如果仅筛去sqrt(n)内因子的倍数,也可以得到所有的素数。复杂度降低为n(loglogn -1),实际上少了n步的操作。
相关文章推荐
- 素数筛法的复杂度
- 返回数组中任意某个重复的数字--时间复杂度O(n)空间复杂度O(1)
- 01-复杂度1 最大子列和问题
- 在O(1)时间复杂度删除链表节点
- 在O(1)时间复杂度删除链表节点
- 七种排序算法及其复杂度
- lintcode 372 在o(1)时间复杂度删除链表节点
- 时间复杂度O(n)空间复杂度O(1)打印二叉树前中后序
- 第二章 数据结构和算法(常见的时间复杂度及比较)
- 在O(1)时间复杂度删除链表节点
- 时间复杂度:O(1)、O(n)、O(n²)、O(nlogn)等是什么意思,白话文解释专业术语。
- <名词解释>算法&时间复杂度
- hihoCoder 1493 : 歌德巴赫猜想 素数筛法
- 时间复杂度与大O记法的理解
- 常见算法时间复杂度比较
- 如何计算时间复杂度
- 经常使用排序算法时间复杂度和空间复杂度简析
- oracle undo 复杂度--oracle核心技术读书笔记四
- 372在O(1)时间复杂度删除链表节点
- Sieve Prime 素数筛法