![](/img/trans.png)
[英]Java : my program “sometimes” wont store the smallest element per row of a 2d array
[英]Smallest way to store a 2D array in java
我試圖生成一組(至少)應為6x6的2D int
數組。 每個數組存儲0到6的值。 我嘗試使用一個簡單的HashSet<int[][]>
來存儲它們(具有512MB的內存),但很快我得到了錯誤
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
進入程序只有很短的路程。
我考慮過的用於存儲數組的選項:
將它們作為long
存儲在基數7中。由於long
不能超過2^63
位,因此最多只能存儲24(24.3717)位數字。
將它們存儲為String
(例如{{0, 0, 0, 1}, {3, 6, 2, 0}}
"00013620"
{{0, 0, 0, 1}, {3, 6, 2, 0}}
"00013620"
{{0, 0, 0, 1}, {3, 6, 2, 0}}
將變成"00013620"
)。 我認為這只會減少4倍的空間,因為char仍然是1個字節。
使用BitSet
或BigInteger
類的東西? 我不知道它們是什么或它們如何工作。
所以我的問題是: 從6到6存儲6 x 6值數組的最小方法是什么? 以上選項有效嗎,還是有更簡單的方法?
注意:如果有必要,我可以使用8GB的內存。
我的代碼(如果需要知道,它與國際象棋有關): n
是數組的大小(寬度和高度),應該可以達到(或超過)6。
public static HashSet<int[][]> getBoards(int[][] data, int zero, int num) {
HashSet<int[][]> ret = new HashSet<int[][]>(0);
if (zero == num) {
ret.add(data);
} else if (zero == 0) {
for (int y = 0; y < n; y++) {
for (int x = 0; x < n; x++) {
for (int i = 1; i < 7; i++) {
int[][] d0 = new int[n][n];
d0[y][x] = i;
ret.addAll(getBoards(d0, 1, num));
}
}
}
} else {
for (int y = 0; y < n; y++) {
for (int x = 0; x < n; x++) {
if (data[y][x] == 0) continue;
HashSet<int[]> moves = getMoves(data[y][x], x, y);
while (moves.iterator().hasNext()) {
int[] m = moves.iterator().next();
for (int i = 0; i < 6; i++) {
int[][] d0 = arrayCopy(data);
d0[m[0]][m[1]] = i;
ret.addAll(getBoards(d0, zero + 1, num));
}
}
}
}
}
return ret;
}
public static HashSet<int[]> getMoves(int piece, int xPos, int yPos) {
HashSet<int[]> ret = new HashSet<int[]>(0);
for (int y = 0; y < n; y++) {
for (int x = 0; x < n; x++) {
if (x == xPos && y == yPos) continue;
switch (piece) {
case 1:
if (y - yPos == 1 && Math.abs(x - xPos) == 1) ret.add(new int[] {y, x});
break;
case 2:
if (Math.abs(y - yPos) + Math.abs(x - xPos) == 3 && x != xPos && y != yPos) ret.add(new int[] {y, x});
break;
case 3:
if (Math.abs(y - yPos) == Math.abs(x - xPos)) ret.add(new int[] {y, x});
break;
case 4:
if (y == yPos || x == xPos) ret.add(new int[] {y, x});
break;
case 5:
if (Math.abs(y - yPos) == Math.abs(x - xPos) || y == yPos || x == xPos) ret.add(new int[] {y, x});
break;
case 6:
if (Math.abs(y - yPos) <= 1 && Math.abs(x - xPos) <= 1) ret.add(new int[] {y, x});
break;
default:
throw new IllegalArgumentException("Unknown Piece Number (" + piece + ")");
}
}
}
return ret;
}
完整錯誤:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at ChessGenerator.arrayCopy(ChessGenerator.java:120)
at ChessGenerator.getBoards(ChessGenerator.java:71)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:56)
at ChessGenerator.main(ChessGenerator.java:23)
編輯:正如@Louis所指出的,我對HashSet
的使用導致了上述錯誤,但是,我仍然用盡內存
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at ChessGenerator.arrayCopy(ChessGenerator.java:119)
at ChessGenerator.getBoards(ChessGenerator.java:70)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:58)
at ChessGenerator.main(ChessGenerator.java:23)
如果您期望HashSet
僅保留唯一的int[][]
並消除重復項,那將不起作用hashCode
int[][]
(和所有數組)的equals
和hashCode
實現是基於身份的。 如果您一直依靠唯一性來保持不同數組的數量少,那將是行不通的; 您將必須將它們包裝在實現正確的hashCode
和equals
的類型中。
您似乎要創建很多板,這很難遵循,但是似乎您基本上在生成6X6大小的所有數組的很大一部分,其中每個單元格可以具有1,2,。,6的任何值。
此類數組的數量為6 ^ 36〜= 10 ^ 28。
這意味着,即使每個陣列只有一個字節(不能為一個字節),您仍然需要10 ^ 16 TB的空間來容納所有字節。
我建議您尋找一種不包括顯式生成所有可能數組的替代方法。
附帶說明一下,表示對象的最低位數是ceil(log_2(6^36)) = 94
,但是要獲得最佳效果將需要大量工作,我不建議這樣做。
最直接但仍具有內存效率的方法是將每個數組存儲為兩個long
,每個字段占用3位(總共3 * 36 = 108個有用位,開銷為20個未使用位)。 盡管理論上的限制還不及此,但是您幾乎可以肯定希望結構與單詞邊界對齊,因此您並沒有真正失去任何東西。 但是,您獲得的好處是,訪問各個字段既簡單又快速,只需要位屏蔽和移位操作即可。
我還將研究堆外存儲選項,以消除所有對象開銷。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.