Java:如何高效地存储布尔型数组[32]?

10

在Java中,我想要存储(>10'000)个长度为32的布尔数组(boolean[])到磁盘,并且以后可以再次读取它们进行进一步的计算和比较。

由于单个数组的长度为32,我想知道是否将其存储为整数值以加快读写速度(在32位机器上)是有意义的。您是否建议使用BitSet,然后转换为int?或者完全不考虑int并使用字节?


1
对你来说,什么更重要:高效的存储还是高效的读写(即快速的读写)? - mikołak
1
你只需要一次写入和读取所有数组,还是需要随机访问特定的数组? - Behe
1
将其视为二维布尔数组是否合理,例如boolean[10000][32]? - Stefan Haustein
到目前为止,我使用了一个二维布尔数组。然而,这个二维数组并不真正代表一个矩阵。这里使用的一个布尔数组可以被视为一个特征向量(用于模式识别);第二个维度只是为了方便而已。 - navige
你进行了什么类型的比较?使用位运算也可能加快速度。 - Stefan Haustein
显示剩余5条评论
2个回答

11

对于二进制存储,使用intDataOutputStream(读取时使用DataInputStream)。

我认为在Java中,布尔数组在内部被存储为字节数组或整数数组,因此您可能希望考虑避免开销并始终保持整数编码,即根本不使用boolean[]

相反,可以这样做:

public class BooleanArray32 {
  private int values;

  public boolean get(int pos) {
    return (values & (1 << pos)) != 0;
  }

  public void set(int pos, boolean value) {
     int mask = 1 << pos;
     values = (values & ~mask) | (value ? mask : 0);
  }

  public void write(DataOutputStream dos) throws IOException {
    dos.writeInt(values);
  }

  public void read(DataInputStream dis) throws IOException {
    values = dis.readInt();
  }

  public int compare(BooleanArray32 b2) {
     return countBits(b2.values & values);
  }

  // From http://graphics.stanford.edu/~seander/bithacks.html
  // Disclaimer: I did not fully double check whether this works for Java's signed ints
  public static int countBits(int v) {
    v = v - ((v >>> 1) & 0x55555555);                    // reuse input as temporary
    v = (v & 0x33333333) + ((v >>> 2) & 0x33333333);     // temp
    return ((v + (v >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24; 
  }
} 

+1,现在,这绝对比BitSet更适合OP的要求。 - Luca Geretti
非常有道理!非常感谢! - navige
修复了 set 中的一个错误,并将静态辅助函数移动到底部。您可能需要仔细检查 bitsInNibble 辅助函数中的位计数。如果您的任务按预期工作,请告诉我们 :) - Stefan Haustein
更新2:将bitcount更改为此处描述的方法:http://graphics.stanford.edu/~seander/bithacks.html - Stefan Haustein
Update2 看起来很棒!非常整洁(链接也非常有趣)!谢谢! - navige
1
追溯到根源,以下是Ian Ashdown在1996年2月15日发布在comp.graphics.algorithms上的帖子链接:https://groups.google.com/d/msg/comp.graphics.algorithms/ZKSegl2sr4c/QYTwoPSx30MJ - seh

1

我强烈印象,任何压缩布尔值的尝试都会增加读写时间(我的错误,显然是因为我忘记吃药了)。相反,您将在所涉及的存储方面获得收益。

BitSet是您业务逻辑方面明智的选择。它在内部存储一个long,您可以将其转换为int。但是,由于BitSet足够谨慎,不会向您显示其私有内容,因此您需要按顺序获取每个位索引。这意味着我猜想与其转换为int,直接使用字节可能没有真正的优势。

因此,Stefan Haustein的自制解决方案(必要时扩展以模仿BitSet)对于您的存储需求更可取,因为您不会产生任何不必要的开销。


第一句话显然不是真的:存储器以字节或更大的单位组织,比内存访问和简单计算慢几个数量级。 - Stefan Haustein
你对组织和内存访问比率的看法是正确的,但你还需要考虑缓存。我会修正我的答案来解决这个问题。 - Luca Geretti
1
我不明白缓存在这里的作用。请注意,这并不是关于压缩的问题,而只是将一个位存储为单个位而不是一个字节或更多字节的问题。 - Stefan Haustein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接