我有一个程序,我需要从byte[][]
数组中删除一组行。我想删除其中没有零的每一行。现在我使用以下方法:
public byte[][] checkRows(byte[][] grid) {
LinkedList<Integer> temp = new LinkedList<Integer>();
boolean willRemove = false;
for (int y = 0; y < grid.length; y++) {
boolean tempCheck = true;
for (int x = 0; x < grid[0].length; x++) {
if (grid[y][x] == 0) {
tempCheck = false;
break;
}
}
if (tempCheck) {
temp.add(y);
willRemove = true;
}
}
if (willRemove) {
int[] rowArray = convert(temp);
return removeRows(grid, rowArray);
}
return grid;
}
public byte[][] removeRows(byte[][] grid, int[] rows) {
int total = rows.length;
int current = 0;
byte[][] retGrid = new byte[grid.length][grid[0].length];
for (int i = total; i < grid.length; i++) {
if (current < total && i-total+current == rows[current]) {
current++;
}
//retGrid[i] = grid[i-total+current].clone();
System.arraycopy(grid[i-total+current], 0, retGrid[i], 0, xsize);
}
return retGrid;
}
public int[] convert(LinkedList<Integer> intList) {
int[] retArray = new int[intList.size()];
for (int i = 0; i < retArray.length; i++) {
retArray[i] = intList.get(i).intValue();
}
return retArray;
}
这为我提供了一种相当快速的方法,可以从2D数组中删除行,并在数组顶部用零行替换它们。有没有更快的方法来实现相同的结果?
如果不清楚脚本是做什么的,那就是删除俄罗斯方块游戏中的完整行。
更新:使用System.arraycopy()
代替clone()
可为小型阵列提供5%的性能提升。
答案 0 :(得分:3)
使用链接列表会删除O(1),请参阅this answer,因为无论如何都必须迭代列表。
起初我认为multidim数组是紧凑的,因为它是一个连续的内存块,但it seems并非如此。因此,您不会失去可能已生效的任何缓存优势。
可惜Java没有值类型(当前),我使用一个而不是一个字节来编码信息。嗯,这不是绝对必要的......
从代码审核的角度来看,在方法willRemove
中使用bool checkRows
是不必要的,因为在这些情况下,temp
将包含多个元素。如果不需要,我会尝试完全消除ArrayList
分配 - 推迟它。
答案 1 :(得分:1)
这个小方法为一维案例执行问题的所需功能。
private static final void onClearFilledRows(final byte[] pTetris, final int pRowLength) {
int i = 0, j = 0;
/* Track the last valid position of row data. */
int lLastValidIndex = 0;
/* Iterate through each row. */
for(i = 0; i < pTetris.length; i += pRowLength) {
/* Iterate through each cell in the row. */
boolean lContainsZero = false;
for(j = i; j < (i + pRowLength) & !lContainsZero; j++) {
lContainsZero |= pTetris[j] == 0;
}
/* This row is valid. Copy it to the last valid index. */
if(lContainsZero) {
System.arraycopy(pTetris, i, pTetris, (lLastValidIndex++ * pRowLength), pRowLength);
}
}
/* Empty the remaining rows. */
for(i = lLastValidIndex * pRowLength; i < pTetris.length; i++) {
/* Set the element to zero. */
pTetris[i] = 0;
}
}
然后可以针对二维情况重新编写该逻辑:
private static final void onClearFilledRows(final byte[][] pTetris) {
int i = 0, j = 0;
/* Track the last valid position of row data. */
int lLastValidIndex = 0;
/* Iterate through each row. */
for(i = 0; i < pTetris.length; i ++) {
/* Iterate through each cell in the row. */
boolean lContainsZero = false;
for(j = 0; j < pTetris[i].length & !lContainsZero; j++) {
lContainsZero |= pTetris[i][j] == 0;
}
/* This row is valid. Copy it to the last valid index. */
if(lContainsZero) {
System.arraycopy(pTetris[i], 0, pTetris[lLastValidIndex++], 0, pTetris[i].length);
}
}
/* Empty the remaining rows. */
for(i = lLastValidIndex; i < pTetris.length; i++) {
for(j = 0; j < pTetris[i].length; j++) {
/* Set the element to zero. */
pTetris[i][j] = 0;
}
}
}
答案 2 :(得分:1)
恕我直言,这太复杂了。放弃LinkedList
,因为这无论如何都是一件可怕的事情。不要费心去收集要删除的索引,而是将要保留的每一行复制到另一个数组中。然后使用arraycopy
覆盖原始文件。
您正在复制整行,但您不必这样做。只需重新排列它们,这样保留下来的行就会掉下来并将完整的行移到顶部并清理它们。没有内存分配。
由于所有复制操作仅适用于一个维度,因此最优化的操作可能无法确定行中是否存在任何零并且(现在和之后)清理某些行。
我想知道它运行的机器是什么,因为我猜它即使是最慢的手机也一定很快。顺便说一句。 CR会更适合。考虑更好的名称,例如tempCheck -> noZeroFound
。