Java BitSet.size() 没有返回我在构造函数中给出的大小

Lau*_*ta1 1 java bit bitset

我有以下代码:

 private BitSet arrayListToBitSet(ArrayList<Boolean> code) {
                // The problem is here, the bitset automatically is created using 64 bits even tho we are clearly 
                    // giving it a max size in constructor, and in the test we are running,
                    // we are only using 9 bits, leading to the rest of the bits being automatically 0, so we need to
                    // search for a way that the size of the bitset is exactly the size of the array list "code"
                int x = code.size(); // With the test I'm running, x = 9;
                BitSet bitset = new BitSet(x);
                System.out.println(bitset.size());
        
                for (int i = 0; i < x; i++)
                {
                    bitset.set(i, code.get(i));
                }
        
                return bitset;
        }
Run Code Online (Sandbox Code Playgroud)

System.out.println() 在控制台上显示 64,尽管它应该只显示 9。

即使当我将 9 硬编码到 BitSet 的构造函数中时,它仍然返回位集的大小为 64。当我制作一个压缩 .txt 文件的程序时,使用 BitSets 而不是布尔值对我来说至关重要,或者如果有人知道在java中操作单个位的另一种方法,它也会有帮助。

在 BitSet.size() 的文档中只说了以下内容

public int size()
Returns the number of bits of space actually in use by this BitSet to represent bit values. The maximum element in the set is the size - 1st element.
Returns:
the number of bits currently in this bit set 
Run Code Online (Sandbox Code Playgroud)
  • Oracle文档

这对我的问题确实没有多大帮助。有谁知道发生这种情况的原因吗?以及如何解决它?多谢。

更多上下文:我正在做的是霍夫曼算法的实现,将给定的 .txt 文件压缩到一个名为“CompressedFile”的新类,该类将存储在电脑内存中。

在上述方法之前发生的事情是,我们计算文本中的字符并将它们保存到哈希映射中,然后使用该哈希映射创建霍夫曼树,一旦我们有了霍夫曼树,我们就用它来获取每个字符的霍夫曼编码对于文本中的字符,给定字符的每个代码都保存在另一个具有以下值对的 HashMap 中:

(char, ArrayList),由于 BitSets 的问题,代码现在是布尔值的 ArrayList。

一旦我们有了这个,我们就把这个 HashMap 交给另一个创建“encodedText”的函数,这是一个存储 tex 的编码版本的 ArrayList,我们通过遍历 .txt 中的每个字符并添加编码值来做到这一点该 char 到“encodedText”变量(回想一下,char 的编码值也保存为 HashMap 中的 ArrayList)。

一旦我们有了完整的 Huffman 代码,arrayListToBitSet 方法就开始发挥作用,它将 ArrayList 版本中的编码文本转换为 BitSet 版本,即要存储在 CompressedText 类中的版本。

我们用于测试目的的 .txt 文件就是这样的:“aaabbc”

在获取霍夫曼树并获取每个字符编码版本之后,值对如下所示(我将使用 0 和 1,以免写 True 和 False):

(a, 0) (b, 11) (c, 10)

因此文本的编码版本将如下所示:000111110

当这个 ArrayList 转换为 BitSet 时,输出(我将 Bitset 打印到控制台)如下所示: 0001111100000000000...(另一个 42 ceros)... 00

所以前 9 位是正确的,但后面的 53 位不应该存在,并且是 cero。如果我像这样保留它,解码后的文本将如下所示:

阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿阿...

与原来有很大不同。解决此问题的一种方法是在 CompressFile 类中包含编码消息的正确大小,因此当我解压缩它时,我只检查确切的位数,但我想知道是否有一种方法不必这样做将这个整数保存在类中(这将为我节省 8 个字节,从总体上看并不算多,变成 8 个字符,但目的是使用尽可能少的内存)。不过,如果没有其他方法,我会将原始大小放入 CompressedFile 类中。

先谢谢您的帮助 :)

Swe*_*per 6

请注意构造函数的文档内容:

创建一个位集,其初始大小足以显式表示索引在 到 范围内的0nbits-1

“足够大”这句话是这里的关键。此构造函数不应创建与您指定的大小完全相同的位集 - 只是足够大以存储您指定的位数。

另请注意类文档中的这一段:

每个位集都有一个当前大小,即该位集当前使用的空间位数。请注意,大小与位集的实现相关,因此它可能会随实现而变化。

BitSet至少在 OpenJDK 中,是通过使用long[]. 这就解释了为什么你会看到 64。要创建一个“足够大”来存储 9 位的位集,至少可以分配一个long[]长度为 1 的位。单个位long是 64 位。

我认为在 JVM 中甚至不可能实现可以恰好存储 9 位的位集。即使您使用 aboolean[]来支持它,每个字节boolean仍然是一个字节(您可能已经知道)。

因此,拥有额外的 ceros 可能会导致在文件的解压缩版本中添加更多字符

如果是这种情况,您可以检查lengthBitSet。它给出了位集中有多少位,减去前导零位。

  • 使用“length”也不合适,因为前导零对于霍夫曼代码很重要(或者至少*可以*)。您必须跟踪哪些位是“真实的”,哪些位仅存在于“BitSet”内部......或者只是使用其他东西 (2认同)