阅读《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和数组的对比结果

然后各测试了三次,测试的结果是这样子的:

clipboard.png

可以看到三次平均下来,BitSet的性能还是稍微好一些的。

引发思考的问题

但是!但是!但是!

我在另外一台电脑上用相同的代码跑出来的结果却很不一样。

另外一台电脑跑出来的结果,利用数组实现(也就是上面的ArrayTest)的速度非常快,经常时间在16-32毫秒之间。而用BitSet实现(也就是上面的BitSetTest)的却是150-160左右。

两台机器的配置是一样的,win7,32位,4GB,3.2GHZ。
一开始以为是编译器的问题,后来发现不用编译器用命令行得到的结果也是有差异的。

算法的原理和实现已经懂了一些,但是带出来了这些问题,有木有大神解释一下啊。


羊都是我吃的
1.4k 声望2.9k 粉丝

将来的你,一定会感谢现在拼命努力的自己。