动态编程:Bits Array Java

时间:2013-12-03 16:43:39

标签: java algorithm memory matrix dynamic-programming

我需要解决一个Dynamic Programming问题,我需要在内存中创建一个N*N大小矩阵。如果我创建的byte[][]矩阵的大小为N = 100000;,则会引发java.lang.OutOfMemoryError: Java heap space错误。

在此矩阵中,我将在特定ithjth索引处存储0或1。所以我的使用仅限于一点,我需要一种方法,这样我每个矩阵单元只能使用1位大小,而不是溢出存储器,在需要仅为1位的单元中保留8位。

我怎样才能做到这一点?

请注意我的关注点并不是增加JVM的堆积,我只是在寻找一种方法来最佳地实现动态问题的解决方案。

3 个答案:

答案 0 :(得分:2)

更新:我刚刚检查过,遗忘了BitSet

BitSet的原始API建立在int索引之上。整数范围超出N * N的范围。因此,您需要自己实施一些东西。一个建议:

public class BetterBitSet {

  private final long[] values;

  public BetterBitSet(int dimension) {
    values = new long[(int) ((long) dimension) * dimension / 8 / 64 + 1];
  }

  public void set(int i, int j, boolean value) {
    long index = index(i, j);
    int arrayIndex = arrayIndex(index);
    if (value) {
        values[arrayIndex] = set(values[arrayIndex], offset(index));
    } else {
        values[arrayIndex] = unset(values[arrayIndex], offset(index));
    }
  }

  public boolean isSet(int i, int j) {
    long index = index(i, j);
    return isSet(values[arrayIndex(index)], offset(index));
  }

  private boolean isSet(long value, int bitIndex) {
    return (value & (1L << bitIndex)) != 0;
  }

  private long set(long value, int bitIndex) {
    return value | (1L << bitIndex);
  }

  private long unset(long value, int bitIndex) {
    return value & ~(1L << bitIndex);
  }

  private long index(int i, int j) {
    return j * 8L + i;
  }

  private int arrayIndex(long index) {
    return (int) index / 64;
  }

  private int offset(long index) {
    return (int) index % 64;
  }
}

如有疑问,请查看BitSet的源代码并尝试类似的内容。

旧答案:问题是byte[][]的每个索引都需要8位,只存储1位信息。这需要9,536 MB用于在堆上分配此数组,因此您的空间不足。这个内存量很可能对您的机器来说太大了。但是,对于存储位,您仍然需要1,192 MB。 (不考虑由BitSet引起的任何开销。)这仍然是一个很高的数字,因此请确保您的机器提供了足够的空间,您必须另外分配给您的JVM实例。

答案 1 :(得分:1)

Java提供了一个名为BitSet的托管位数据结构。我说这是管理的,因为Java没有用于存储位的本机类型,而是BitSet将各个位存储为long的组件,并保留long[]以支持组。这是一种非常高效的存储方法,但implementation of BitSet每64位中有6位用于“寻址”,这相当于原始存储层中10%的开销。

这意味着您可以通过保留并仔细查找自己的BitSet来节省long[]存储空间,但代价是代码中存在一些复杂性和风险。除非你对空间有很大的限制,否则可能不值得保存BitSet的~10%原始开销。

上述两种解决方案都是一维的位数组,这也许值得一无所知。通过将一维数组视为行的连接,您可以轻松地将二维数组转换为一维数组(至少,在这种情况下,您似乎假设行宽相等)。寻址矩阵中的特定单元格只是:

row * (row_width) + column

答案 2 :(得分:0)

在许多情况下,您不需要所有子问题来评估当前问题,所以我会建议使用hashmap的DP问题的递归自顶向下解决方案来存储解决方案。一旦使用了子问题,您可以将其从hashmap中删除以防止溢出。 有时会有轻微的性能损失但会阻止内存完全错误。

Memoization