数据结构与算法—稀疏数组

基本介绍

当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。

实际需求

相信大家都知道 “五子棋”,或者类似这种棋牌类游戏。它的棋盘就能看成一个二维数组,并且都有一个默认的值,当选手进行下棋操作的时候,会对此二维数组的某行某列的值进行修改。
棋盘与二维数组的对应关系如下图:

从上图可以看到,棋盘对应的二维数组中,没有进行操作的地方,默认值是0,如果程序把这种数据都记录上,是没有意义的。因此,这里就需要将上面的二维数组转换为 “稀疏数组”。

二维数组 转 稀疏数组


这张图就是转换之后的结果。
arr[0][0] = 原始数组的行数
arr[0][1] = 原始数组的列数
arr[0][2] = 有效数字的个数
其他值就存放对应的行列坐标和值。

接下来就用代码实现一下。

    /**
     * TODO 创建原始的二维数组
     */
    private static int[][] createTwoArray() {
        int[][] twoArray = new int[11][11];
        twoArray[2][3] = 1;
        twoArray[3][4] = 2;
        return twoArray;
    }

首先初始化原始数组,定义一个11行,11列的二维数组。这里就以棋子为例,黑子为 “1”,白子为 “2”,给定两个有效数据,然后进行稀疏数组的转换。

    /**
     * TODO 通过 原始的二维数组 得到 稀疏数组
     *
     * @param twoArray 原始的二维数组
     */
    private static int[][] getSparseArray(int[][] twoArray) {
        // 1. 先遍历二维数组 得到非0数据的个数
        int sum = 0;
        for (int[] oneArray : twoArray) {
            for (int data : oneArray) {
                if (data != 0) {
                    sum++;
                }
            }
        }
        System.out.println("非0数据的个数为:" + sum);
        // 2. 创建对应的稀疏数组
        int[][] sparseArray = new int[sum + 1][3];
        // 3. 给稀疏数组第一行赋值(索引为 0)
        sparseArray[0][0] = twoArray.length;
        sparseArray[0][1] = twoArray[0].length;
        sparseArray[0][2] = sum;

        // 4. 遍历原始二维数组,将非0的值放入 稀疏数组中
        int count = 0;
        for (int i = 0; i < twoArray.length; i++) {
            for (int j = 0; j < twoArray[i].length; j++) {
                if (twoArray[i][j] != 0) {
                    count++;
                    sparseArray[count][0] = i;
                    sparseArray[count][1] = j;
                    sparseArray[count][2] = twoArray[i][j];
                }
            }
        }
        return sparseArray;
    }

基本上代码都有注释,就不做过多的讲解了。编写测试类看看结果。

    public static void main(String[] args) {
        // 1. 得到原始的二维数组
        int[][] twoArray = createTwoArray();
        // 输出原始的二维数组
        System.out.println("原始的二维数组:");
        for (int[] oneArray : twoArray) {
            for (int data : oneArray) {
                System.out.print(data + "\t");
            }
            System.out.println();
        }
        // 打印分割线
        printLine();

        // 2. 将原始的二维数组变为稀疏数组
        int[][] sparseArray = getSparseArray(twoArray);
        // 输出稀疏数组
        System.out.println("原始的二维数组转为稀疏数组是:");
        for (int[] sparseOne : sparseArray) {
            for (int data : sparseOne) {
                System.out.print(data + "\t");
            }
            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	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数据的个数为:2
原始的二维数组转为稀疏数组是:
11	11	2	
2	3	1	
3	4	2	

稀疏数组 转 二维数组

上面已经讲了二维数组转稀疏数组了,但是我们还需要将它转回原来的二维数组。这个就非常简单了,直接上代码。

    /**
     * TODO 将 稀疏数组 恢复成 二维数组
     *
     * @param sparseArray 稀疏数组
     * @return void
     */
    private static int[][] restoreTwoArray(int[][] sparseArray) {
        // 1. 读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
        int[][] twoArray = new int[sparseArray[0][0]][sparseArray[0][1]];

        // 2. 读取稀疏数组后几行的数据(从第二行开始),并赋值给 原始的二维数组
        for (int i = 1; i < sparseArray.length; i++) {
            twoArray[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
        }
        return twoArray;
    }

同样通过测试类查看结果:

恢复之后的二维数组是:
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	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	

完整代码

上面讲了 二维数组 和 稀疏数组 之间的转换。就拿“五子棋程序”来说,它还有其他额外的功能,例如:存档、读档、悔棋等等…通过下面这个简单的流程,实现简易版的 “五子棋程序”。

棋盘初始化 --> 二维数组 --> 稀疏数组 --> 存档(写入文件) --> 读档(读取文件) --> 稀疏数组 --> 二维数组 --> 棋盘

因为重点在稀疏数组,所以下面只是增加了文件存取的功能,并不涉及五子棋下棋的操作,还望各位读者理性阅读。

public class SparseArray {

    public static void main(String[] args) {
        // 1. 得到原始的二维数组
        int[][] twoArray = createTwoArray();
        // 输出原始的二维数组
        System.out.println("原始的二维数组:");
        for (int[] oneArray : twoArray) {
            for (int data : oneArray) {
                System.out.print(data + "\t");
            }
            System.out.println();
        }
        // 打印分割线
        printLine();

        // 2. 将原始的二维数组变为稀疏数组
        int[][] sparseArray = getSparseArray(twoArray);
        // 输出稀疏数组
        System.out.println("原始的二维数组转为稀疏数组是:");
        for (int[] sparseOne : sparseArray) {
            for (int data : sparseOne) {
                System.out.print(data + "\t");
            }
            System.out.println();
        }
        // 打印分割线
        printLine();

        // 3. 将 稀疏数组存入文件中 [存档功能]
        System.out.println("将稀疏数组存入文件中");
        outPutSparseArrayToFile(sparseArray);
        // 打印分割线
        printLine();

        // 4. 读取 文件中的稀疏数组 [读档功能]
        int[][] sparseArrayDataFromFile = inputSparseArrayFromFile();
        System.out.println("从文件中读取的稀疏数组的值是:");
        for (int[] oneArray : sparseArrayDataFromFile) {
            for (int data : oneArray) {
                System.out.print(data + "\t");
            }
            System.out.println();
        }
        // 打印分割线
        printLine();

        // 5. 将稀疏数组恢复成原始的二维数组
        int[][] restoreTwoArray = restoreTwoArray(sparseArrayDataFromFile);
        // 输出恢复之后的 二维数组
        System.out.println("恢复之后的二维数组是:");
        for (int[] oneArray : restoreTwoArray) {
            for (int data : oneArray) {
                System.out.print(data + "\t");
            }
            System.out.println();
        }
    }

    /**
     * TODO 创建原始的二维数组
     */
    private static int[][] createTwoArray() {
        int[][] twoArray = new int[11][11];
        twoArray[2][3] = 1;
        twoArray[3][4] = 2;
        return twoArray;
    }

    /**
     * TODO 通过 原始的二维数组 得到 稀疏数组
     *
     * @param twoArray 原始的二维数组
     */
    private static int[][] getSparseArray(int[][] twoArray) {
        // 1. 先遍历二维数组 得到非0数据的个数
        int sum = 0;
        for (int[] oneArray : twoArray) {
            for (int data : oneArray) {
                if (data != 0) {
                    sum++;
                }
            }
        }
        System.out.println("非0数据的个数为:" + sum);
        // 2. 创建对应的稀疏数组
        int[][] sparseArray = new int[sum + 1][3];
        // 3. 给稀疏数组第一行赋值(索引为 0)
        sparseArray[0][0] = twoArray.length;
        sparseArray[0][1] = twoArray[0].length;
        sparseArray[0][2] = sum;

        // 4. 遍历原始二维数组,将非0的值放入 稀疏数组中
        int count = 0;
        for (int i = 0; i < twoArray.length; i++) {
            for (int j = 0; j < twoArray[i].length; j++) {
                if (twoArray[i][j] != 0) {
                    count++;
                    sparseArray[count][0] = i;
                    sparseArray[count][1] = j;
                    sparseArray[count][2] = twoArray[i][j];
                }
            }
        }
        return sparseArray;
    }

    /**
     * TODO 将 稀疏数组 恢复成 二维数组
     *
     * @param sparseArray 稀疏数组
     * @return void
     */
    private static int[][] restoreTwoArray(int[][] sparseArray) {
        // 1. 读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
        int[][] twoArray = new int[sparseArray[0][0]][sparseArray[0][1]];

        // 2. 读取稀疏数组后几行的数据(从第二行开始),并赋值给 原始的二维数组
        for (int i = 1; i < sparseArray.length; i++) {
            twoArray[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
        }
        return twoArray;
    }

    /**
     * TODO 将 稀疏 数组 存入 文件中(下棋中的 存档功能)
     *
     * @param sparseArray 稀疏数组
     */
    private static void outPutSparseArrayToFile(int[][] sparseArray) {
        FileWriter writer = null;
        BufferedWriter bufferedWriter = null;
        try {
            writer = new FileWriter("D:/idea_workspace/my-project/algorithm-dataStructure/data-structure/src/file/a.txt");
            bufferedWriter = new BufferedWriter(writer);

            for (int[] oneArray : sparseArray) {
                for (int data : oneArray) {
                    bufferedWriter.write(data + "\t");
                }
                bufferedWriter.write("\n");
            }
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert bufferedWriter != null;
                bufferedWriter.close();
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * TODO 从 文件中 读取 稀疏数组(下棋中的 读档功能)
     */
    private static int[][] inputSparseArrayFromFile() {
        FileReader reader = null;
        BufferedReader bufferedReader = null;
        // 1. 读取的所有数据的集合
        List<String> strLineList = new ArrayList<>();
        try {
            reader = new FileReader("D:/idea_workspace/my-project/algorithm-dataStructure/data-structure/src/file/a.txt");
            bufferedReader = new BufferedReader(reader);
            String line = "";
            while ((line = bufferedReader.readLine()) != null) {
                strLineList.add(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert reader != null;
                reader.close();
                assert bufferedReader != null;
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 2. 拿到第一行,初始化稀疏数组
        String firstLineStr = strLineList.get(0);
        String[] firstLineVal = firstLineStr.split("\t");
        int[][] sparseArray = new int[strLineList.size()][firstLineVal.length];

        // 3. 遍历 设置 稀疏数组的值
        for (int i = 0; i < strLineList.size(); i++) {
            String[] values = strLineList.get(i).split("\t");
            for (int j = 0; j < values.length; j++) {
                sparseArray[i][j] = Integer.parseInt(values[j]);
            }
        }
        return sparseArray;
    }


    private static void printLine() {
        System.out.println("-----------------------------------------");
    }
}

输出结果,这里就不给出了,感兴趣的读者,直接复制完整代码运行即可。

谋事在人成事在天

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值