稀疏数组

152 阅读4分钟

稀疏数组

实例题目:

例如,在一个棋盘游戏中,我们要保存棋盘的当前状态并持久化到硬盘,并且下次打开期盼的时候可以继续上一把未完成的棋盘。

//例如这是一个棋盘,其中1代表白子,2代表黑子
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	1	0	0	0	0	0	0	0	
0	0	0	0	2	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	1	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	

在这样的11*11的棋盘中,传统的方式是保存整个棋盘的状态,这里就需要用到11 * 11 的二维数组,这就会使用大量的内存空间去保存这些0,而这些0没有任何意义。

这种情况就需要稀疏数组去实现数组的压缩保存,其原理是只将那些有效的元素放进数组存储,而那些无意义的元素则不存储。

//avatar

由上图我们可以看到,我们将原本的11 * 11的二维数组,压缩成了一个3*3的二维数组,这样就节约了大量的空间

这种稀疏数组中元素的存储,在第一行存储的是棋盘的信息

  • 【0】【0】:棋盘的行数
  • 【0】【1】:棋盘的列数
  • 【0】【2】:棋盘中有效元素的个数

除去第一行之外,剩下的每条行都对应着棋盘中有效元素的行、列、和元素的值


代码实现

/**
 * 稀疏数组:
 * 实现棋盘的保存和重开
 */
public class SparseArray {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //创建一个11*11的棋盘
        //初始数组1
        int[][] chessArr1 = new int[11][11];
        //白子为1,黑子为2
        chessArr1[2][3] = 1;
        chessArr1[3][4] = 2;
        chessArr1[7][6] = 1;

        //遍历棋盘,保存有效的元素个数
        int sum = 0;
        System.out.println("初始数组:");
        for (int[] rows : chessArr1) {
            for (int item : rows) {
                System.out.printf("%d\t", item);
                if (item != 0) sum++;
            }
            System.out.println();
        }

        //创建稀疏数组
        System.out.println("稀疏数组:");
        int[][] sparseArr = new int[sum + 1][3];
        sparseArr[0][0] = 11;
        sparseArr[0][1] = 11;
        sparseArr[0][2] = sum;

        //遍历原数组,获取原数组中有效元素的索引
        int account = 0;
        for (int i = 0; i < chessArr1.length; i++) {
            for (int j = 0; j < chessArr1[i].length; j++) {
                //如果是有效元素,则存入稀疏数组中
                if (chessArr1[i][j] != 0) {
                    account++;
                    sparseArr[account][0] = i;
                    sparseArr[account][1] = j;
                    sparseArr[account][2] = chessArr1[i][j];
                }
            }
        }

        //最后的结果数组
        System.out.println("稀疏数组的结果:");
        for (int[] rows : sparseArr) {
            for (int item : rows) {
                System.out.printf("%d\t", item);
            }
            System.out.println();
        }

        //作业:将稀疏数组本地保存
        //对象的序列化
        FileOutputStream fos = new FileOutputStream("map.data");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(sparseArr);
        os.flush();

        //将本地的稀疏数组取出
        //对象的反序列化
        FileInputStream fis = new FileInputStream("map.data");
        ObjectInputStream is = new ObjectInputStream(fis);
        //继续棋局
        sparseArr = (int[][]) is.readObject();

        //解析稀疏数组
        //创建一个新的空白数组
        int[][] chessArr2 = new int[sparseArr[0][0]][sparseArr[0][1]];

        //根据稀疏数组中的元素给新数组赋值
        for (int i = 1; i < sparseArr.length; i++) {
            chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }

        //打印新数组
        System.out.println("新数组:");
        for (int[] rows : chessArr2) {
            for (int item : rows) {
                System.out.printf("%d\t", item);
            }
            System.out.println();
        }
    }
}

输出的结果

初始数组:
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	1	0	0	0	0	0	0	0	
0	0	0	0	2	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	1	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
稀疏数组:
稀疏数组的结果:
11	11	3	
2	3	1	
3	4	2	
7	6	1	
新数组:
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	1	0	0	0	0	0	0	0	
0	0	0	0	2	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	1	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	0	

进程已结束,退出代码0