阅读《Java核心技术》的时候,读到了BitSet这个集合。
有一个例子是Eratosthenes 之筛算法,这个算法的主要作用是查找一定范围之内的所有质数,对此比较感兴趣,所以用Boolean数组和BitSet各做了一遍,又在两台电脑上各实现了两种算法。
在实现的过程中,遇到了一些问题,会在最后提出,这里不说废话了,先说正事~
Eratosthenes 之筛算法思路
由于一个合数总是可以分解成若干个质数的乘积,那么如果把质数(最初只知道2是质数)的倍数都去掉,那么剩下的就是质数了。
例如要查找100以内的质数,首先2是质数,把2的倍数去掉;此时3没有被去掉,可认为是质数,所以把3的倍数去掉;再到5,再到7,7之后呢,因为8,9,10刚才都被去掉了,而100以内的任意合数肯定都有一个因子小于10(100的开方),所以,去掉,2,3,5,7的倍数后剩下的都是质数了。
Boolean数组实现
public class ArrayTest
{
public static void main(String[] args)
{
int sum = 0;
final int TOTAL = 2_000_001;
Boolean[] array = new Boolean[TOTAL];
long startTime = System.currentTimeMillis();
for(int i = 2;i<TOTAL;i++)
{
array[i] = true;
}
for(int i = 2;i<Math.sqrt(TOTAL);i++)
{
for(int j = i;i*j<TOTAL;j++)
{
array[i*j] = false;
}
}
long endTime = System.currentTimeMillis();
for(int i = 2;i<TOTAL;i++)
{
if(true==array[i])
{
sum ++;
}
}
System.out.println("There is "+ sum + " prime number");
System.out.println("Total time is "+ (endTime - startTime));
}
}
BitSet实现
import java.util.BitSet;
public class BitSetTest
{
public static void main(String[] args)
{
int sum = 0;
final int TOTAL = 2_000_001;
BitSet aBitSet = new BitSet(TOTAL);
long startTime = System.currentTimeMillis();
for(int i = 2;i<TOTAL;i++)
{
aBitSet.set(i);
}
for(int i = 2;i<Math.sqrt(TOTAL);i++)
{
for(int j = i;i*j<TOTAL;j++)
{
aBitSet.clear(i*j);
}
}
long endTime = System.currentTimeMillis();
for(int i = 2;i<TOTAL;i++)
{
if(true==aBitSet.get(i))
{
sum ++;
}
}
System.out.println("There is "+ sum + " prime number");
System.out.println("Total time is "+ (endTime - startTime));
}
}
BitSet和数组的对比结果
然后各测试了三次,测试的结果是这样子的:
可以看到三次平均下来,BitSet的性能还是稍微好一些的。
引发思考的问题
但是!但是!但是!
我在另外一台电脑上用相同的代码跑出来的结果却很不一样。
另外一台电脑跑出来的结果,利用数组实现(也就是上面的ArrayTest)的速度非常快,经常时间在16-32毫秒之间。而用BitSet实现(也就是上面的BitSetTest)的却是150-160左右。
两台机器的配置是一样的,win7,32位,4GB,3.2GHZ。
一开始以为是编译器的问题,后来发现不用编译器用命令行得到的结果也是有差异的。
算法的原理和实现已经懂了一些,但是带出来了这些问题,有木有大神解释一下啊。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。