数据结构 day01 稀疏矩阵

14 阅读4分钟

需求:

image.png

模拟棋盘数据的压缩、持久化与恢复

  1. 原始数据:一个 11×11 的二维数组模拟棋盘,仅包含 2 个非 0 有效数据(黑棋 1、蓝棋 2),其余位置为 0

  2. 核心转换:将这个稀疏的二维数组压缩为稀疏数组 —— 首行存储原始数组的行数、列数和有效数据数,后续每行存储一个非 0 数据的「行坐标、列坐标、值」。

  3. 持久化与恢复

    • 把生成的稀疏数组写入文件实现持久化(存档)。
    • 再从文件中读取稀疏数组,恢复为原始的 11×11 二维数组(读档),完成棋盘数据的完整闭环。

代码实现:

public class SparseArrayTest02 {
    // 定义文件路径常量,便于维护
    private static final String SPARSE_ARRAY_FILE_PATH = "D:\JavaTest\SparSearray\sparsearray.txt";

    public static void main(String[] args) {
        // 1. 创建原始棋盘数组(11x11)
        int[][] originalChessboard = createOriginalChessboard();

        // 2. 原始数组转换为稀疏数组
        int[][] sparseArray = convertToSparseArray(originalChessboard);
        System.out.println("=== 生成的稀疏数组 ===");
        printArray(sparseArray);

        // 3. 将稀疏数组写入文件
        writeSparseArrayToFile(sparseArray, SPARSE_ARRAY_FILE_PATH);

        // 4. 从文件读取稀疏数组
        int[][] readSparseArray = readSparseArrayFromFile(SPARSE_ARRAY_FILE_PATH);
        if (readSparseArray != null) {
            System.out.println("\n=== 从文件读取的稀疏数组 ===");
            printArray(readSparseArray);
        }

        // 5. 稀疏数组转换回原始数组
        int[][] restoredChessboard = convertToOriginalArray(sparseArray);
        System.out.println("\n=== 恢复后的原始棋盘数组 ===");
        printArray(restoredChessboard);
    }

    /**
     * 功能1:创建原始棋盘数组(11x11,模拟落子)
     * @return 初始化后的11x11二维数组
     */
    public static int[][] createOriginalChessboard() {
        int[][] chessboard = new int[11][11];
        chessboard[1][2] = 1;  // 模拟1号棋子
        chessboard[2][3] = 2;  // 模拟2号棋子
        return chessboard;
    }

    /**
     * 功能2:原始二维数组转换为稀疏数组
     * @param originalArr 原始二维数组(大部分元素为0)
     * @return 压缩后的稀疏数组
     */
    public static int[][] convertToSparseArray(int[][] originalArr) {
        // 步骤1:统计原始数组中非0元素的个数
        int validDataCount = countValidData(originalArr);

        // 步骤2:初始化稀疏数组(首行存元信息,后续行存非0数据)
        int[][] sparseArr = new int[validDataCount + 1][3];
        sparseArr[0][0] = originalArr.length;         // 原始数组行数
        sparseArr[0][1] = originalArr[0].length;      // 原始数组列数
        sparseArr[0][2] = validDataCount;             // 非0元素个数

        // 步骤3:填充稀疏数组的非0数据
        int sparseRowIndex = 1; // 稀疏数组行索引(从1开始,0行是元信息)
        for (int i = 0; i < originalArr.length; i++) {
            for (int j = 0; j < originalArr[i].length; j++) {
                if (originalArr[i][j] != 0) {
                    sparseArr[sparseRowIndex][0] = i;
                    sparseArr[sparseRowIndex][1] = j;
                    sparseArr[sparseRowIndex][2] = originalArr[i][j];
                    sparseRowIndex++;
                }
            }
        }
        return sparseArr;
    }

    /**
     * 辅助方法:统计原始数组中非0元素的个数
     * @param originalArr 原始二维数组
     * @return 非0元素数量
     */
    public static int countValidData(int[][] originalArr) {
        int count = 0;
        for (int[] row : originalArr) {
            for (int value : row) {
                if (value != 0) {
                    count++;
                }
            }
        }
        return count;
    }

    /**
     * 功能3:稀疏数组转换回原始二维数组
     * @param sparseArr 稀疏数组
     * @return 恢复后的原始二维数组
     */
    public static int[][] convertToOriginalArray(int[][] sparseArr) {
        // 步骤1:从稀疏数组首行获取原始数组的行列信息,初始化原始数组
        int[][] originalArr = new int[sparseArr[0][0]][sparseArr[0][1]];

        // 步骤2:填充原始数组的非0数据
        for (int i = 1; i < sparseArr.length; i++) {
            int row = sparseArr[i][0];
            int col = sparseArr[i][1];
            int value = sparseArr[i][2];
            originalArr[row][col] = value;
        }
        return originalArr;
    }

    /**
     * 功能4:将稀疏数组写入指定文件(逗号分隔)
     * @param sparseArr 待写入的稀疏数组
     * @param filePath 文件保存路径
     */
    public static void writeSparseArrayToFile(int[][] sparseArr, String filePath) {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))) {
            // 逐行写入稀疏数组,每行格式:行,列,值
            for (int[] row : sparseArr) {
                String line = row[0] + "," + row[1] + "," + row[2];
                bw.write(line);
                bw.newLine(); // 换行
            }
            System.out.println("\n稀疏数组已成功写入文件:" + filePath);
        } catch (IOException e) {
            System.err.println("写入稀疏数组到文件失败!路径:" + filePath);
            e.printStackTrace();
        }
    }

    /**
     * 功能5:从指定文件读取稀疏数组(逗号分隔)
     * @param filePath 文件路径
     * @return 读取后的稀疏数组(失败返回null)
     */
    public static int[][] readSparseArrayFromFile(String filePath) {
        int[][] sparseArr = null;
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            // 步骤1:读取首行(元信息:行数、列数、非0数据数)
            String firstLine = br.readLine();
            if (firstLine == null) {
                System.err.println("文件为空,无法读取稀疏数组!");
                return null;
            }
            String[] metaData = firstLine.split(",");
            int originalRows = Integer.parseInt(metaData[0]);
            int originalCols = Integer.parseInt(metaData[1]);
            int validDataCount = Integer.parseInt(metaData[2]);

            // 步骤2:初始化稀疏数组
            sparseArr = new int[validDataCount + 1][3];
            sparseArr[0][0] = originalRows;
            sparseArr[0][1] = originalCols;
            sparseArr[0][2] = validDataCount;

            // 步骤3:读取后续行,填充非0数据
            String line;
            int sparseRowIndex = 1;
            while ((line = br.readLine()) != null) {
                String[] data = line.split(",");
                sparseArr[sparseRowIndex][0] = Integer.parseInt(data[0]);
                sparseArr[sparseRowIndex][1] = Integer.parseInt(data[1]);
                sparseArr[sparseRowIndex][2] = Integer.parseInt(data[2]);
                sparseRowIndex++;
            }
        } catch (IOException e) {
            System.err.println("读取稀疏数组文件失败!路径:" + filePath);
            e.printStackTrace();
        } catch (NumberFormatException e) {
            System.err.println("文件内容格式错误!请确保每行是"数字,数字,数字"格式");
            e.printStackTrace();
        }
        return sparseArr;
    }

    /**
     * 功能6:通用数组打印方法(支持稀疏数组/原始数组)
     * @param arr 待打印的二维数组
     */
    public static void printArray(int[][] arr) {
        if (arr == null) {
            System.out.println("数组为空,无法打印!");
            return;
        }
        for (int[] row : arr) {
            for (int value : row) {
                System.out.print(value + "\t");
            }
            System.out.println();
        }
    }
}

最终效果:

image.png