簡體   English   中英

最高效的數據結構 memory 存儲二維數組值(Java)

[英]Most memory efficient data structure to store 2D array values (Java)

所以我正在嘗試針對以下問題制作最高效的算法 memory:我們有一個無限的地下室。

現在我們從網格上沒有硬幣開始,所以結果總是可以預測的。 我為此使用了二維數組。 我想知道是否有另一種方法。 我在考慮 Hashmaps 或 Hashsets 但我不知道那是如何工作的

僅跟蹤訪問過的有硬幣的位置。

一個 HashSet,其中每個條目都是一個 x,y 對; 最初它是空的。

如果 x,y 不在 map 中,則它沒有硬幣 - 添加一個條目。

如果 x,y 在 map 中,它有一個硬幣 - 刪除條目。

memory 利用率應該高於覆蓋您“可能”訪問的任何地方的數組,並且您不必猜測數組有多大才足夠大。

如果你想在你的項目中引入一個Map ,那是可以的。

作為一個鍵,您可以生成一個由xy坐標組合而成的String ,如果您不需要表示除了硬幣是否存在以外的其他情況, Boolean將是一個方便的選項作為值。

HashMap可以完全替代代碼中的basement數組 除了map之外,您還需要引入兩個int字段來表示xy方向的大小。

您可以按照與array相同的方式預填充map 您可以生成隨機起始值,而不是使用相同的默認值初始化所有坐標。

在游戲循環中,您可以像這樣切換映射到特定圖塊的值:

map.put(key, !map.get(key));

或者通過使用 Java 8 方法compute()這種方式:

hasCoinByTileKey.compute(key, (k, v) -> !v);

要查明圖塊是否包含硬幣,請使用get()

if (map.get(key)) {
    // do something
}

性能方面,它會表現得相當好,但比基於數組的解決方案稍慢。 因為在引擎蓋下, HashMap由數組支持。 簡而言之,每個數組元素構成一個桶,對應於特定范圍的哈希值。 映射條目將形成一個鏈表,如果幾個鍵映射到同一個桶(在一定閾值之后,列表將被轉換為樹)。 這同樣適用於HashSet ,因為HashSet class 是在HashMap之上構建的。

如果你用HashMap替換一個數組,你的Basement class 可能看起來像這樣:

public class Basement {
    public static void main(String[] args) {
        new Basement(20, 20).update();
    }

    private static final int STEPS = 20;
    private Map<String, Boolean> hasCoinByTileKey = new HashMap<>();
    private List<Tile> path = new ArrayList<>();
    private int rows;
    private int cols;

    private record Tile(int x, int y) {}

    public Basement(int rows, int cols) {
        this.rows = rows;
        this.cols = cols;

        Random random = new Random();
        for (int row = 0; row < cols; row++) {
            for (int col = 0; col < cols; col++) {
                hasCoinByTileKey.put(getKey(row, col), random.nextBoolean());
            }
        }
    }

    public static String getKey(int row, int col) {
        return row + "," + col;
    }

    public void update() {
        path.clear(); // cleaning the previous keys
        int x = rows / 2;
        int y = cols / 2;
        int orientation = 0;
        /*
        0 - up
        1 - right
        2 - left
        3 - down
        */
        for (int steps = 0; steps < STEPS; steps++) {
            path.add(new Tile(x, y)); // updating the path will current coordinates
            String key = getKey(x, y);
            if (!hasCoinByTileKey.get(key)) {
                hasCoinByTileKey.compute(key, (k, v) -> !v); // toggling the boolean value of the tile
                if (orientation == 0) {
                    y += 1;
                    orientation = 1;
                } else if (orientation == 1) {
                    x += 1;
                    orientation = 3;
                } else if (orientation == 2) {
                    x -= 1;
                    orientation = 0;
                } else {
                    y -= 1;
                    orientation = 2;
                }
            } else {
                hasCoinByTileKey.compute(key, (k, v) -> !v); // toggling the boolean value of the tile
                if (orientation == 0) {
                    y -= 1;
                    orientation = 2;
                } else if (orientation == 1) {
                    x -= 1;
                    orientation = 0;
                } else if (orientation == 2) {
                    x += 1;
                    orientation = 3;
                } else {
                    y += 1;
                    orientation = 1;
                }
            }
        }
        System.out.println(path.size());
        System.out.println(path);
        this.print();
    }

    public void print() {
        boolean[][] grid = new boolean[rows][cols];
        for (Tile tile: path) {
            grid[tile.x][tile.y] = true;
        }
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                System.out.print(grid[row][col] ? 'a' : ' ');
            }
            System.out.println();
        }
    }
}

為了打印路徑,在更新方法的執行過程中使用一個單獨的列表來跟蹤路徑。 持有坐標的 Object 是一條record

main() - 演示

public static void main(String[] args) {
    new Basement(20, 20).update();
}

Output - 20 步(模式與您的示例不同,因為大約一半的瓷磚將預先填充硬幣

                    
        aaaa        
        aaaa        
        aaa         
        aaaaa       
         aaaa       
          aa        
                    

public final class Basement {

    private final Map<Integer, Set<Integer>> board = new HashMap<>();
    private final Tile curTile = new Tile();
    private final Axis row = new Axis();
    private final Axis col = new Axis();

    public void nextStep() {
        if (hasCoin())
            pickUpCoinAndRotate();
        else
            placeCoinAndRotate();

        col.update(curTile.col);
        row.update(curTile.row);
    }

    private boolean hasCoin() {
        return hasCoin(curTile.col, curTile.row);
    }

    private boolean hasCoin(int col, int row) {
        return board.getOrDefault(row, Set.of()).contains(col);
    }

    private void placeCoinAndRotate() {
        board.computeIfAbsent(curTile.row, val -> new HashSet<>()).add(curTile.col);
        curTile.rotateClockwise();
    }

    private void pickUpCoinAndRotate() {
        board.computeIfAbsent(curTile.row, val -> new HashSet<>()).remove(curTile.col);
        curTile.rotateCounterclockwise();
    }

    private void print() {
        for (int row = this.row.min; row <= this.row.max; row++) {
            for (int col = this.col.min; col <= this.col.max; col++)
                System.out.print(hasCoin(col, row) ? 'a' : '.');

            System.out.println();
        }
    }

    private enum Orientation {
        UP {
            @Override
            public Orientation rotateClockwise(Tile curTile) {
                curTile.col++;
                return RIGHT;
            }

            @Override
            public Orientation rotateCounterclockwise(Tile curTile) {
                curTile.col--;
                return LEFT;
            }
        },
        RIGHT {
            @Override
            public Orientation rotateClockwise(Tile curTile) {
                curTile.row++;
                return DOWN;
            }

            @Override
            public Orientation rotateCounterclockwise(Tile curTile) {
                curTile.row--;
                return UP;
            }
        },
        DOWN {
            @Override
            public Orientation rotateClockwise(Tile curTile) {
                curTile.col--;
                return LEFT;
            }

            @Override
            public Orientation rotateCounterclockwise(Tile curTile) {
                curTile.col++;
                return RIGHT;
            }
        },
        LEFT {
            @Override
            public Orientation rotateClockwise(Tile curTile) {
                curTile.row--;
                return UP;
            }

            @Override
            public Orientation rotateCounterclockwise(Tile curTile) {
                curTile.row++;
                return DOWN;
            }
        };

        public abstract Orientation rotateClockwise(Tile curTile);

        public abstract Orientation rotateCounterclockwise(Tile curTile);
    }

    private static final class Tile {

        private int row;
        private int col;
        private Orientation orientation = Orientation.UP;

        public void rotateClockwise() {
            orientation = orientation.rotateClockwise(this);
        }

        public void rotateCounterclockwise() {
            orientation = orientation.rotateCounterclockwise(this);
        }

    }

    private static final class Axis {

        private int min;
        private int max;

        public void update(int cur) {
            min = Math.min(min, cur);
            max = Math.max(max, cur);
        }

    }

    public static void main(String... args) {
        Basement basement = new Basement();

        for (int steps = 0; steps < 200; steps++) {
            basement.nextStep();
            basement.print();
            System.out.println();
        }
    }

}

演示:

..aaaa...
.a....a..
aaa....a.
aaaaaaaa.
.aa.a..a.
.a...a.aa
..aaa.aaa
aaa....a.
...aaaa..

使用稀疏矩陣

    class Node {  
int row;  
int col;  
int value;  
Node next;  
Node(int r, int c, int val)   
{ row = r; col = c; this.value = val; }  
}  
public class Sparse{  
public static void main(String[] args)  
{  
/*Assume a 4x4 sparse matrix */  
int sparseMatrix[][] = {  
{0, 0, 1, 2},  
{3, 0, 0, 0},  
{0, 4, 5, 0},  
{0, 6, 0, 0}  
};  
Node start = null; /*Start with the empty list*/  
Node tail = null;  
int k = 0;  
for (int i = 0; i < 4; i++)  
for (int j = 0; j < 4; j++)  
{  
if (sparseMatrix[i][j] != 0) /*Pass only non-zero values*/  
{  
Node temp = new Node(i, j, sparseMatrix[i][j]);  
temp.next = null;  
if(start == null){  
start = temp;  
tail=temp;  
}  
else{  
tail.next = temp;  
tail = tail.next;  
}  
}  
}  
Node itr = start;  
while(start != null){  
System.out.println(start.row  + " " + start.col + " " + start.value);  
start = start.next;  
}  
}  
}  

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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