簡體   English   中英

在Java中存儲2D數組的最小方法

[英]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

進入程序只有很短的路程。

我考慮過的用於存儲數組的選項:

  1. 將它們作為long存儲在基數7中。由於long不能超過2^63位,因此最多只能存儲24(24.3717)位數字。

  2. 將它們存儲為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個字節。

  3. 使用BitSetBigInteger類的東西? 我不知道它們是什么或它們如何工作。

所以我的問題是: 從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[][] (和所有數組)的equalshashCode實現是基於身份的。 如果您一直依靠唯一性來保持不同數組的數量少,那將是行不通的; 您將必須將它們包裝在實現正確的hashCodeequals的類型中。

您似乎要創建很多板,這很難遵循,但是似乎您基本上在生成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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM