一、案例

五子棋程序,只有两种颜色的子,连成五个就gameover。可能一个棋盘能放下100枚棋子,但是总占用空间只有不到10个,游戏就over了。那么这样存储到本地file的话,空间是极大的浪费的。这就引出了稀疏数组。
数据结构和算法之稀疏数组_Java数组

二、稀疏数组应用场景

当一个数组中大部分元素都是0(或是同一个值)的时候,就可以用稀疏数组来保存此数组。

三、什么是稀疏数组

1、图解

先有个原始数组,8*7的规模,如下
数据结构和算法之稀疏数组_Java数组_02

2、分析

明显发现0值的数量远大于有效数据(这里非0值代表有效数据)。而且是个数组形式,所以稀疏数组来了!拆解成下稀疏数组有如下几点:

  • 先统计出原始数组的总行数、总列数、总有效数据数作为稀疏数组的第一行。
  • 将有效数据的行列的位置以及数值存储到稀疏数组中。

比如上面的表格换成稀疏数组的存法就如下:
数据结构和算法之稀疏数组_Java数组_03

可以发现:
稀疏数组永远都是三列。
原始数组存法的话需要87=56个元素空间
稀疏数组存法的话需要11
3=33个元素空间,效果很明显

3、代码

用代码证明上述图片,代码中有详细的关键性注释,一看就懂。

package com.chentongwei.struct.sparsearray;

/**
 * Description: 稀疏数组
 *
 * @author TongWei.Chen 2019-12-12 14:39:08
 */
public class MySparseArray3 {
    public static void main(String[] args) {
        int[][] originArray = new int[8][7];
        originArray[0][2] = 12;
        originArray[0][4] = 2;
        originArray[1][1] = 1;
        originArray[2][3] = -5;
        originArray[3][5] = 10;
        originArray[4][0] = 1;
        originArray[6][0] = 55;
        originArray[6][3] = 4;
        originArray[7][0] = 7;
        originArray[7][4] = 20;
        System.out.println("---------------------原始数组---------------------");
        // print原始数组
        print(originArray);
        System.out.println("---------------------稀疏数组---------------------");
        // 原始数组转稀疏数组
        int[][] spraseArray = originToSparse(originArray);
        print(spraseArray);
        System.out.println("---------------------原始数组---------------------");
        // 稀疏数组转原始数组
        int[][] originArray2 = sparseToOrigin(spraseArray);
        print(originArray2);
    }

    // print
    private static void print(int[][] array) {
        for (int[] arr : array) {
            for (int data : arr) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
    }

    // 原始数组->稀疏数组
    private static int[][] originToSparse(int[][] originArray) {

        // 先找到有效元素行(个)数
        int count = 0;
        for (int i = 0; i < originArray.length; i++) {
            for (int j = 0; j < originArray[i].length; j ++) {
                if (originArray[i][j] != 0) {
                    count ++;
                }
            }
        }

        // 为什么是count + 1?因为count代表有效数据行数,但是再顶部还有一个总的行数、列数、值数
        int[][] spraseArray = new int[count + 1][3];
        // 为稀疏数组的第一行赋值
        spraseArray[0][0] = originArray.length;
        spraseArray[0][1] = originArray[0].length;
        spraseArray[0][2] = count;

        // 组装稀疏数组
        int index = 0;
        for (int i = 0; i < originArray.length; i++) {
            for (int j = 0; j < originArray[i].length; j ++) {
                if (originArray[i][j] != 0) {
                    index ++;
                    spraseArray[index][0] = i;
                    spraseArray[index][1] = j;
                    spraseArray[index][2] = originArray[i][j];
                }
            }
        }

        return spraseArray;
    }

    // 稀疏数组->原始数组
    private static int[][] sparseToOrigin(int[][] sparseArray) {
        // 先构建出原始数组的行列
        int[][] originArray = new  int[sparseArray[0][0]][sparseArray[0][1]];
        // 再往上面卯值
        for (int i = 1; i < sparseArray.length; i ++) {
            for (int j = 0; j < sparseArray[i].length; j ++) {
                originArray[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][j];
            }
        }
        return originArray;
    }
}

4、结果

数据结构和算法之稀疏数组_Java数组_04