今天在学习Java核心技术第九章集合框架中的BitSet时,遇到了这个算法。Eratosthenes筛子算法时一个查找素数的方法,这并不是查找素数的最好方法,但是测试编译程序性能的一种流行的基准。
一、BitSet位集
BitSet类用于存放一个位序列,它将位包装在字节里,比使用Boolean对象的ArrayList更加高效。
BitSet类的常用方法有
BitSet(int initialCapacity) 创建一个位集,规定了它的容量。 index从0开始,长度会随需要增加。
int length() 返回位集的而逻辑长度,即位集的最高设置位的索引 + 1.
boolean get(int bit) 获得一个位
void set(int bit) 设置一个位为true
void clear(int bit) 清除一个位为false
void and(BitSet set) 两个位集相“与”
void or(BitSet set) 两个位集“或”
void xorBitSet set) 两个位集“异或”
void andNot(BitSet set) 清除这个位集中对应另一个位集中设置的位
二、Eratosthenes筛子算法
本算法的思想如下
1,创建一个从2到n的连续数组
2,创建一个变量p等于2(第一个素数)
3,从p2开始,标记所有大于等于p2,让其中一个因子p自增,且乘积小于等于n的程式。例如p(p+1),p(p+2),……
4,找到大于p的第一个未被标记的数字,让p等于它,重复第三步。
下面我们用图片来更加具体的解释一下这个过程 (以下部分转自https://www.geeksforgeeks.org/sieve-of-eratosthenes/ 如有侵权,请联系我删除)
Let us take an example when n = 50. So we need to print all print numbers smaller than or equal to 50.
We create a list of all numbers from 2 to 50.
According to the algorithm we will mark all the numbers which are divisible by 2 and are greater than or equal to the square of it.
Now we move to our next unmarked number 3 and mark all the numbers which are multiples of 3 and are greater than or equal to the square of it.
We move to our next unmarked number 5 and mark all multiples of 5 and are greater than or equal to the square of it.
We continue this process and our final table will look like below:
So the prime numbers are the unmarked ones: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47.
Thanks to Krishan Kumar for providing above explanation.
三、代码实现
下面我们给出两种实现:第一种使用BitSet位集来标记筛选出去的数字索引
int n = 50; BitSet b = new BitSet(n + 1); int count = 0; int i; for (i = 2; i <= n; i++) { b.set(i); } i = 2; while (i * i <= n) { if (b.get(i)) { count++; System.out.println(i); int k = 2* i; while (k <= n) { b.clear(k); k += i; } } i++; } while (i <= n) { if (b.get(i)) { System.out.println(i); count++; } i++; }
第二种用布尔数组实现
void sieveOfEratosthenes(int n) { // Create a boolean array "prime[0..n]" and initialize // all entries it as true. A value in prime[i] will // finally be false if i is Not a prime, else true. boolean prime[] = new boolean[n+1]; for(int i=0;i<n;i++) prime[i] = true; for(int p = 2; p*p <=n; p++) { // If prime[p] is not changed, then it is a prime if(prime[p] == true) { // Update all multiples of p for(int i = p*p; i <= n; i += p) prime[i] = false; } } // Print all prime numbers for(int i = 2; i <= n; i++) { if(prime[i] == true) System.out.print(i + " "); } }