稀疏数组及其应用

稀疏数组及其应用上图左侧是一个 11 11 的棋盘 目前棋盘上有两个棋子 一黑一蓝 如果要求把此时棋盘的状态保存起来 存盘退出 该如何做 即此时已经把稀疏数组进行了存盘操作 当然是使用如上图右侧的一个 11 11 的二维数组 把磁盘记录下来 其中 1 表示黑子 2 表示蓝子 sparse 英 sp s adj 稀少的 至此成功解析硬盘文件 恢复成稀疏数组 如上图的第二行表示原始数组中第一行第四列的数据为 22 如上图的第一行表示 原始数组为 6 行 7 列共 8 个非零值 要把棋盘转化为同样大小的二维数组并没有难度


1,稀疏数组的应用场景

进入正题之前可以先记一个单词:

  • sparse 英[spɑːs]:adj. 稀少的; 稀疏的; 零落的

看一个稀疏数组相关的实际需求:
在这里插入图片描述

:上图左侧是一个11*11的棋盘,目前棋盘上有两个棋子,一黑一蓝。如果要求把此时棋盘的状态保存起来(存盘退出),该如何做?

有人可能会认为可以使用如上图右侧的一个11×11的二维数组,把磁盘记录下来。其中1表示黑子,2表示蓝子,这固然可行,但不是最佳的方案。

实际上此处使用数据结构中的稀疏数组性能会更优秀。

要把棋盘转化为同样大小的二维数组并没有难度。但该二维数组会有很多值默认为0,记录了很多没有意义的数据。因此可以使用稀疏数组对二维数组进行压缩,从而实现优化。


二维数组的定义:

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

稀疏数组的处理方法:

  • 记录数组一共有几行几列,有多少不同的值
  • 把具有不同值的元素的行、列、值记录在一个小规模的数组中,从而缩小程序的规模,如下图:
    在这里插入图片描述
    上图中原数组记录42个数据,化为稀疏数组后只需要记录9*3=27个数据。




稀疏数组第一行数据表示:原始数组共几行,共几列,共几个非零值。
如上图的第一行表示,原始数组为6行7列共8个非零值。

稀疏数组除第一行外的每行(非首行)分别记录每一个非零值所在行列坐标和数据值大小。
如上图的第二行表示原始数组中第一行第四列的数据为22。

注意:行列均从0开始计数。


2,稀疏数组转换的思路分析

在这里插入图片描述
二维数组转稀疏数组思路:

  • ①遍历原始的二维数组,得到有效数据个数sum。(知道有效数据个数可以知道稀疏数组的大小)
  • ②根据sum创建稀疏数组,sparseArray int[sum+1] [3]。表示创建一个(sum+1)行3列的稀疏数组。(稀疏数组列数3是固定的,分别为行,列,值)
  • ③将二维数组的有效数据存入到稀疏数组中

稀疏数组转二维数组思路:

  • ①先读取稀疏数组的第一行,根据第一行的数据可以创建原始的二维数组;如上图是chessArr2=int[11] [11]
  • ②再读取稀疏数组后几行的数据,并赋值给原始二维数组即可

以上过程再配合Java的IO操作(写入磁盘文件,文件读入内存)就可以实现类似下棋游戏过程中的“存盘退出”,“恢复上盘棋局” 的操作。


3,稀疏数组的代码实现(Java语言)

3.1,二维数组转化为稀疏数组:

将上述图中的二维数组转化为稀疏数组:

 //创建一个原始的二维数组:11*11 //其中:0表示没有棋子;1表示黑子;2表示蓝子 int chessArray1[][]=new int[11][11]; chessArray1[1][2]=1; //表示第2行,第3列值为1 chessArray1[2][3]=2; //表示第3行,第4列值为2 //输出原始的二维数组查看 System.out.println("原始的二维数组如下:"); for (int[] row:chessArray1){ 
         for (int data:row){ 
         System.out.printf("%d\t",data); //格式化输出 } System.out.println(); //换行 } //将二维数组转化为稀疏数组 //第一步:遍历二维数组。计算有效数据个数(非0数据个数) int sum=0; for (int i=0;i<chessArray1.length;i++){ 
         //遍历行。此时chessArray1.length为11 for (int j=0;j<11;j++){ 
         //遍历列 if (chessArray1[i][j]!=0){ 
         sum++; } } } System.out.println(sum); //2 //创建对应的稀疏数组 int sparseArray[][]=new int[sum+1][3]; //给稀疏数组赋值 sparseArray[0][0]=11; //稀疏数组第一行第一列为11 sparseArray[0][1]=11; sparseArray[0][2]=sum; //遍历二维数组,将非零值存放到sparseArray中 int count=0; //引入一个count用来记录是第几个非零数据 for (int i=0;i<chessArray1.length;i++){ 
         for (int j=0;j<11;j++){ 
         if (chessArray1[i][j]!=0){ 
         count++; sparseArray[count][0]=i; //列很好确定,行需要找规律:第一个非0数据放在稀疏数组第二行,第二个非0数据放在稀疏数组第三行。。。因此引入一个count用来记录是第几个非零数据 sparseArray[count][1]=j; sparseArray[count][2]=chessArray1[i][j]; } } } //输出稀疏数组查看 System.out.println(); System.out.println("得到的稀疏数组为如下形式:"); for(int i=0;i<sparseArray.length;i++){ 
         System.out.printf("%d\t%d\t%d\t\n",sparseArray[i][0],sparseArray[i][1],sparseArray[i][2]); // \t为制表符相当于tab,\n为换行 } System.out.println(); 

3.2,稀疏数组还原为二维数组

 //将稀疏数组恢复成二维数组 //1,先读取稀疏数组的第一行,根据第一行数据初始化二维数组 int chessArray2[][]=new int[sparseArray[0][0]][sparseArray[0][1]]; //此时二维数组大小确定,内容全是0 //2,读取稀疏数组后几行数据,并赋给初始化好的二维数组 for (int i=1;i<sparseArray.length;i++){ 
         //i=1表示从稀疏数组的第二行开始读取 chessArray2[sparseArray[i][0]][sparseArray[i][1]]=sparseArray[i][2]; //认真理解 } System.out.println(); //输出恢复后的二维数组查看 System.out.println(); System.out.println("恢复后的二维数组如下:"); for (int[] row:chessArray2){ 
         for (int data:row){ 
         System.out.printf("%d\t",data); //格式化输出 } System.out.println(); //换行 } 

4,IO流实现稀疏数组的读写磁盘操作

实现以下操作:

  • 需求一:在以上基础上,将稀疏数组保存在磁盘上,如:保存为map.data
  • 需求二:恢复原来的数组时,读取map.data进行恢复

需求一解决方案:

 //使用IO流将稀疏数组保存磁盘文件map.data进行存档 File destFile = new File("map.data"); BufferedWriter bw = null; try { 
          bw=new BufferedWriter(new FileWriter(destFile)); for (int[] row:sparseArray){ 
          for (int data:row){ 
          bw.write(data+"\t"); } bw.write("\n"); //换行 } } catch (IOException e) { 
          e.printStackTrace(); } finally { 
          if (bw!=null){ 
          try { 
          bw.close(); } catch (IOException e) { 
          e.printStackTrace(); } } } 
//从硬盘文件中读取数据,并转换为稀疏数组。为了便于读取,使用一个list对稀疏数组中的元素进行存储 BufferedReader br= null; File srcFile = new File("map.data"); List<Integer> list = new ArrayList<>(); try { 
          br=new BufferedReader(new FileReader(srcFile)); String line; while ((line=br.readLine())!=null){ 
          //读取每一行的数据 String[] str = line.split("\t"); //返回一个个元素构成的数组 for (int i=0;i<str.length;i++){ 
          list.add(Integer.parseInt(str[i])); //把每个数组元素都添加到list集合中去,便于读取 } } } catch (IOException e) { 
          e.printStackTrace(); } finally { 
          if (br!=null){ 
          try { 
          br.close(); } catch (IOException e) { 
          e.printStackTrace(); } } } //读取list集合数据,得到稀疏数组的行数。(有了行数就可以创建稀疏数组) //其中list.get(2)取到的是数组中第三个元素,即稀疏数组第一行第三列元素,代表了非零元素个数。非零元素个数加一即为稀疏数组行数 int row=list.get(2)+1; //list中get方法的参数为索引 System.out.println("稀疏数组的行数为:"+row); //3 //创建稀疏数组 int sparseArray2[][] = new int[row][3]; //sparseArray2[0][0]=list.get(0); //sparseArray2[0][1]=list.get(1); //sparseArray2[0][2]=list.get(2); //sparseArray2[1][0]=list.get(3); //sparseArray2[1][1]=list.get(4); //sparseArray2[1][2]=list.get(5); //找到循环赋值规律 //进行循环赋值(此处是读取文件内容恢复到稀疏数组核心) int j=0; //通过j控制行 for (int i=0;i<list.size();i=i+3){ 
          //稀疏数组每行三个元素,赋值完一行,循环一次 sparseArray2[j][0]=list.get(i); sparseArray2[j][1]=list.get(i+1); sparseArray2[j][2]=list.get(i+2); j++; //每一行的三个数赋值结束,当前行数随之增加一 } //输出解析出来的稀疏数组样式查看 System.out.println(); System.out.println("解析文件后得到的稀疏数组为如下形式:"); for(int i=0;i<sparseArray2.length;i++){ 
          System.out.printf("%d\t%d\t%d\t\n",sparseArray2[i][0],sparseArray2[i][1],sparseArray2[i][2]); } 

代码执行结果:

在这里插入图片描述
至此成功解析硬盘文件,恢复成稀疏数组!此即为“续上盘”功能。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/217755.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 上午8:50
下一篇 2026年3月18日 上午8:50


相关推荐

  • PyCharm中批量查找及替换

    PyCharm中批量查找及替换选中需要操作的字符 nbsp Ctrl R 替换 Ctrl Shift F 全局查找 Ctrl Shift R 全局替换源自 PyCharm 中批量查找及替换 Ella Wu 博客园 http www cnblogs com wuaihua p 7597017 html

    2026年3月27日
    3
  • Checked异常和Runtime异常的区别_JAVA运行时异常

    Checked异常和Runtime异常的区别_JAVA运行时异常目录一、运行时异常1、什么是RuntimeExceptioin2、运行时异常的特点3、如何运用运行时异常二、运行时异常和ckecked异常的区别1、机制上2、逻辑上一、运行时异常1、什么是运行时异常程序在运行过程中出现的异常,RumtimeException是Exception的一个子类我们可以查看Jav

    2022年9月30日
    7
  • linux curl命令详解_curl详解

    linux curl命令详解_curl详解curl(CommandLineUniformResourceLocator),即在命令行中利用URL进行数据或者文件传输。https://curl.haxx.se/这是curl的官网。可以从上面的官网地址下载最新的curl版本。同时可以在官网看出curl支持的各种协议(如HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS,POP3,POP3S等)、使用途径、…

    2025年8月13日
    4
  • naviacat激活码[最新免费获取]

    (naviacat激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html1STL5S9V8F-eyJsaWNlbnNlSW…

    2022年3月27日
    90
  • 中文人物关系图谱构建与应用项目(人物关系抽取,关系抽取评测)

    中文人物关系图谱构建与应用项目(人物关系抽取,关系抽取评测)ChinesePersonRelationGraphChinesePersonRelationGraph,personrelationshipextractionbasedonnlpmethods.中文人物关系知识图谱项目,内容包括中文人物关系图谱构建,基于知识库的数据回标,基于远程监督与bootstrapping方法的人物关系抽取,基于知识图谱的知识问答等应用.项目地址:htt…

    2022年6月26日
    54
  • 面试题 HashMap 数据结构 实现原理

    面试题 HashMap 数据结构 实现原理数据结构HashMap的数据结构数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。数组:数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。哈希表那

    2022年5月12日
    49

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号