数据结构和算法 —— 稀疏数组 的简单介绍及实例应用

问题思考

在这里插入图片描述
还是紧接着上图的这个问题,比如,我们可以创建一个11 * 11的二维数组,其中0表示没有棋子,1表示黑子,2表示蓝子。。。当然是没有问题的。
但是如上图,我们发现,如果我们使用该二维数组,那么里面有很多值默认值是0,因此记录了很多没有意义的数据,所以我们便引入了 —— 稀疏数组。

简介

当一个数组中的大部分元素是0,或者为同一个值的时候,就可以使用稀疏数组来保存该数组。
当然,上面的解释可能会很抽象,我们先看下稀疏数组处理数据的方法:

  1. 稀疏数组的第一行记录数组一共有几行几列,有多少非0的不同的值
  2. 把非0的不同的值的元素的行、列、值记录在一个小规模的数组中,从而缩小程序的规模
    看不懂没关系,因为它确实很抽象,我们来看图并举例说明 ↓

举例说明

在这里插入图片描述

  • 如图,左边是一个矩阵,我们可以创建一个6 * 7的二维数组来表示它,但是同样的,我们也会发现里面会有很多是0的元素
  • 那么我们就来创建一个稀疏数组,来看看稀疏数组在这种情况下,对应二维数组的优越性。
  1. 根据上面所说的稀疏数组的概念的第一条并结合左图的矩阵,我们知道,这个矩阵一共有6行7列,非0的不重复的元素个数一个是8个,所以,我们稀疏矩阵的第一行的数据便可以写出来了,也就是6 7 8
  2. 然后再根据概念的第二条并结合左图的矩阵:
  • 举例:如左边矩阵中22这个值,它所在的行数是0,列数是3,值是22,原先二维数组中的这个元素可以在稀疏数组中表示为:0 3 22。
  1. 以此类推,其他的元素便也可以相应地放到稀疏数组中去。
    转换完之后,我们得到的稀疏数组是9 * 3的,而原先未转换之前的二维数组是6 * 7 > 9 * 3,因此这个问题就因为稀疏数组得到了优化。

那么既然稀疏数组这么优秀,我们在解决问题的时候怎么把二维数组转换为稀疏数组呢?
或者简单的说:二维数组和稀疏数组在程序上是如何来实现的呢?
我们首先回到最开始的的棋盘问题 ↓

棋盘问题

然后我们再回到棋盘问题上来

需求

  • 如下图,编写一个五子棋程序,有存盘退出和续上盘的功能。
    在这里插入图片描述

思路

  • 使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等)
  • 把稀疏数组存盘,并且可以从新恢复原来的二维数组数
  • 整体思路分析
  1. 我们可以创建一个11*11的二维数组,其中0表示没有棋子,1表示黑子,2表示蓝子。。。当然没有问题
  2. 既然我们认识到稀疏数组可以对这个11*11的二维数组做优化,我们就要考虑怎么把它转化为稀疏数组

分析

  • 我们可以先来分析,11*11的二维数组转化之后的稀疏数组是什么样子的,然后再用程序来实现
    在这里插入图片描述
  • 根据上面的对二维数组和稀疏数组的举例说明,转化之后的稀疏数组如图所示,显然,原先的11 * 11的二维数组被简化为了3 * 3的稀疏数组,要简单的多了。下面我们来看看这个二维数组转换为稀疏数组的代码实现

代码实现(二维数组 → 稀疏数组)

  • 话不多说,直接上代码
  //二维数组转换为稀疏数组
    @Test
    public void test22() {
        //创建一个原始的二维数组11*11
        //其中0表示没有棋子,1表示黑子,2表示蓝子
        int[][] chessArr = new int[11][11];
        chessArr[1][2] = 1;
        chessArr[2][3] = 2;
        //输出原始的二维数组
        System.out.println("原始的二维数组:");
        for (int[] rows : chessArr) {
            for (int data : rows) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
        //二维数组转换为稀疏数组
        //稀疏数组
        //1、第一行记录原先的二维数组一共有几行几列,有多少非0的不同的值
        //2、把具有不同值的元素的行、列、值记录在一个小规模的数组中,从而缩小程序的规模
        //分析:
        //二维数组转换为稀疏数组,需要哪些数据
        //1、需要先定义一个稀疏数组,确定原先的二维数组的行,列,不同的值的个数
        //2、然后,把第一步获取的行、列,不同值的个数,赋值给稀疏数组的第一行
        //3、然后,遍历原始的二维数组,获取数值的行、列,如果该数值不是0,赋值给稀疏数组
        //实现:
        //定义原始二维数组的行row
        int row = 0;
        //定义原始二维数组的列list
        int list = 0;
        //定义非0不同值的个数sum
        int sum = 0;
        for (int[] rows : chessArr) {
            row++;
            list = 0;
            for (int data : rows) {
                list++;
                if (data != 0) {
                    sum++;
                }
            }
        }
        System.out.println("原始二维数组的非0的不同值的个数是: " + sum);
        System.out.println("原始二维数组的行数是: " + row);
        System.out.println("原始二维数组的列数是: " + list);

        int[][] multiArr = new int[sum + 1][3];
        multiArr[0][0] = row;
        multiArr[0][1] = list;
        multiArr[0][2] = sum;

        //定义count,用于记录原先二维数组中的非0数据要放到稀疏数组中的哪一行
        int count = 0;
        for (int i = 0; i < chessArr.length; i++) {
            for (int j = 0; j < chessArr[i].length; j++) {
                if (chessArr[i][j] != 0) {
                    count++;
                    multiArr[count][0] = i;
                    multiArr[count][1] = j;
                    multiArr[count][2] = chessArr[i][j];
                }
            }
        }
        System.out.println();
        //打印转换完成的稀疏数组
        System.out.println("打印转换完成的稀疏数组: ");
        for (int i = 0; i < multiArr.length; i++) {
            System.out.printf("%d\t%d\t%d\t", multiArr[i][0], multiArr[i][1], multiArr[i][2]);
            System.out.println();
        }
    }

打印结果

  • 程序执行后,打印结果如下所示:
    在这里插入图片描述
  • ↑ 以上,我们便完成了二维数组 → 稀疏数组的转换
    既然二维数组可以转换为稀疏数组,那么稀疏数组怎么转换为二维数组呢?

代码实现(稀疏数组 → 二维数组)

  • OK!上代码!
        //已知稀疏数组multiArr,把稀疏数组转换为二维数组
        //分析
        //把稀疏数组转换为二维数组,都需要哪些东西
        //创建二维数组,我们需要知道这个二维数组的的行数、列数、以及非0元素的值的个数
        // 而行数、列数、非0元素的值的个数我们都可以获取到,就是稀疏数组的第一行的三个数据:行数、列数、非0元素的值的个数
        //然后创建完二维数组之后,我们需要给这个二维数组赋值
        //怎么给这个二维数组赋值呢?
        //需要遍历当前的稀疏数组,然后给二维数组赋值
        int rows = multiArr[0][0];
        int lists = multiArr[0][1];
        System.out.println("从稀疏数组中获取到原二维数组的行数是: " + rows);
        System.out.println("从稀疏数组中获取到原二维数组的行数是: " + lists);
        int counts = 0;
        int[][] chessArrTrans = new int[rows][lists];
        //开始遍历稀疏数组
        for (int i = 1; i < multiArr.length; i++) {
            counts ++;
            for (int j = 0; j < multiArr[i].length; j++) {
                int transRow = multiArr[i][0];
                int transList = multiArr[i][1];
                chessArrTrans[transRow][transList] = multiArr[i][2];
            }
            System.out.println();
        }
        //打印转换完成的二维数组
        System.out.println("打印转换完成的二维数组: ");
        for (int[] chessArrTransRows : chessArrTrans) {
            for (int chessArrTransData : chessArrTransRows) {
                System.out.printf("%d\t", chessArrTransData);
            }
            System.out.println();
        }

打印结果

  • 程序执行后,打印结果如下所示:
    在这里插入图片描述
  • ↑ 以上,我们便完成了稀疏数组 → 二维数组的转换

拓展

要求:

  • 在前面的基础上,将稀疏数组保存到磁盘上,比如 map.data
  • 从稀疏数组恢复到原来的二维数组时,读取map.data 进行恢复
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值