【问题标题】:Copying only first 2 dimensions of 3D array仅复制 3D 数组的前 2 个维度
【发布时间】:2013-02-13 02:27:04
【问题描述】:

我将以下 3D 数组设置为两个程序状态之间的缓冲区。

private boolean state [][][] = new boolean [20][20][2];

我正在尝试从

复制所有内容
state[0-19][0-19][1]

state[0-19][0-19][0]

目前我正在使用 for 循环,效果很好,但我不禁觉得有更好的方法。我知道我可以只使用两个单独的 2D 数组并做一个简单的复制,但我很想看看有没有办法解决这个问题。

当前循环:

for (int i=0;i<20;i++){
        for (int j=0;j<20;j++){
            state[i][j][0]=state[i][j][1];
    }
}

【问题讨论】:

  • 要知道它是否可以做得比你拥有的更好,我们实际上必须看看你拥有什么。
  • 对我来说,for 循环很有意义。你会怎么称呼“更好”?更快?
  • @JoeriHendrickx 我想我正在寻找更高效的东西。我知道 System.arraycopy() 可以为单独的数组完成这项工作,但我无法让它在单个数组中工作
  • 为什么要复制?你想要两组重复值吗?还是有其他原因?

标签: java arrays multidimensional-array


【解决方案1】:

有时您可以将内部循环替换为System.arraycopy,这样会更快。但我相信不在你的内存布局中。

如果可能,请考虑更新引用而不是复制数组。回想一下,java 中的“多维”数组实际上是数组的数组。

特别是,

 boolean[] tmp = multi[0];
 multi[0] = multi[1];
 multi[1] = tmp;

交换两个数组引用,成本接近于零。这比复制然后覆盖旧值快很多。但有时你需要一个副本(如果你不覆盖旧值),那么你不能这样做。

请注意,您不应盲目这样做:

 multi[0][0] = 1;
 multi[1] = multi[0];
 multi[1][0] = 0;
 System.err.println(multi[0][0]);

将打印0,因为现在multi[0]multi[1] 指向同一个嵌套数组,您应该使用过。

 multi[1] = multi[0].clone();

请注意,克隆也不是,因此multi.clone() 将指向与multi 相同的嵌套数组。 Java 中没有内置的深度克隆或深度数组复制,无论哪种方式都需要使用循环。

但同样,如果您想将第二个元素复制到 许多数组 中的第一个元素,那么这些都不起作用。这是你的内存布局的问题。

回忆一下你的数据结构在内存中的样子:

 boolean[][][] -> boolean[][] -> boolean[]{ 0, 1 }
              \               \> boolean[]{ 0, 1 }
               \> boolean[][] -> boolean[]{ 0, 1 }
                              \> boolean[]{ 0, 1 }

您想复制每个数组中的一个元素。它们可以在你的内存中全部(每个boolean[]... 都是它自己的对象!),所以没有办法用原语来加速 - 数据是分散的。如果可能的话,也许考虑改变你的内存布局

还要考虑 boolean 数组的替代方案。布尔值占用 1 个字节的内存,但只存储一位(请注意,这可以更快,所以它本身还不错!)。但有时将整个布尔数组存储在BitSetlong 中,然后使用实际的位操作是有意义的。但是收获,有时确实值得,有时却很痛苦。

【讨论】:

  • 请注意,这是 3 维的。 clone 只会为我测试的二维数组生成一个浅拷贝。您的第一种方法仅在数组声明不同时才有效([2] 是第一个维度,而不是最后一个维度)。
  • @nhahtdh 我看不出您的链接与我所说的有何关联或矛盾。
  • 这个问题是关于 3D 的,你的例子使用了 2D 数组。应该如何处理有一些不同。 1) 仅当您重新排列维度[2][20][20] 2) multi.clone() != multi,但multi.clone()[1] == multi[1] 由于共享子数组时,才能交换引用。根据JLS,子数组是共享的。 3) clone 适用于 multi[0](返回一个副本,因为 multi[0] 的类型是一维数组),但它可能会造成混淆,因为 OP 使用的是 3D 数组。
  • 欢迎您添加额外的维度。它没有太大变化。只有最后一个维度是“本机”数组。任何更高的维度都是坚固的。至于multi.clone,我明确表示它们引用了相同的数组,并且副本不深。
  • 那是你错的地方(或者措辞非常混乱)。 multi.clonemulti 不同,只有子数组是共享的。
【解决方案2】:

我喜欢 nhahtdh 重新组织维度的解决方案,但请注意,如果您复制参考,那么如果您稍后更改 state[0]state[1] 将反映更改,反之亦然(请注意,实际上可能是你想要什么)。引用可以在 2 个地方访问,但只能在一个地方存储内容 - 旧的指针/引用混淆。单元测试是你的朋友:-)

如果你有一个维数组,Arrays.copyOf() 方法可以帮助避免一些循环代码。但请记住,某些sometype[] 对象的副本会将reference 复制到该对象,而不是所有单独的sometype 对象。

您当然可以开始使用.clone() 甚至序列化来获得sometype[] 对象的“深层”副本,但这会比嵌套循环更复杂。

【讨论】:

  • 我提出的方法不是复制,而是交换。制作真正的副本需要在某处循环。我没有建议直接分配,所以不会发生有趣的事情。
猜你喜欢
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 2017-01-28
  • 1970-01-01
  • 2021-12-19
  • 1970-01-01
相关资源
最近更新 更多