【1】背景

如下图所示,这里有一个 15 × 15 的棋盘,如果现在要让你通过编码的方式,让你将这盘棋局保存起来,你会怎么做呢?

面对行列数据的保存,我相信大多人第一时间都会想到用二维数组进行保存。

【2】普通数组保存棋盘数据

比如,我们可以将棋盘进行抽象化,用一个 15 × 15 的二维数组来表示,然后用 0 表示空点,用 1 表示白子,用 2 表示黑子,于是就可以抽象为如下模样。

于是,我们可以通过如下代码,将数据保存到二维数组中。

/*** 将棋盘数据保存为二维数组*/
public static int[][] saveChess() {// 初始化棋盘(大小为 15 * 15),int默认为0(即空点)int[][] arr = new int[15][15];// 保存白子(用1表示)arr[5][5] = 1;arr[7][5] = 1;arr[6][7] = 1;// 保存黑子(用2表示)arr[6][6] = 2;arr[7][6] = 2;arr[8][6] = 2;arr[7][7] = 2;return arr;
}

【3】普通数组的不足之处

上面,我们通过了一个最普通的方法,将棋盘数据保存在了一个二维数组中,整个数组我们用了 15 × 15(共 225)个点来保存数据,其中有 218 个点都是空的。实际来说,我们只需要将有价值的黑白子保存起来即可,因为只要我们知道黑白子数据,以及棋盘的大小,那么这 218 个空点是可以不用进行保存的。

把这样没有价值的数据起来,不但会浪费存储空间的大小,如果写入到磁盘中,还会增大 IO 的读写量,影响性能,这就是用普通二维数组来表示棋盘数据的不足之处。

那么,针对以上情况,我们该如何将我们的数据格式进行优化呢?于是就引出了我们接下来的稀疏数组的概念。

【4】稀疏数组

所谓稀疏数组,从字面上我们也可以得知,它仍然是一个数组,他的作用就是将一个对应的数组数据进行优化,比如,我们将上面的二维数组进行优化。

我们可以定义一个数组,只记录黑白子的数据,具体如下:

从这个表中,我们可以只看到有价值的数据了,如果我们再将这个表抽象为一个二维数组,那么他的大小就是 7 * 3 = 21 个点了。

这相对之前的200多个点来说,确实少了许多节点,节省了很多存储空间。

但只这样保存也是不够的,因为我们并没有保存原棋盘的大小,那么我们不妨约定增加一行,保存原来棋盘的大小(二维数组的大小),那么我们可以用如下进行表示:

这里我们约定用第1行数据来记录原二维数组的规模,第 1 个值为原数组总行数,第 2 个值为原数组列数,第 3 个值为有价值数据的总数。

这样,我们就将原数组数据,优化为了一个稀疏数组。

【4】二维数组转稀疏数组

根据上面的原理,我们就可以通过代码方式,将原来的普通二维数组,优化为一个稀疏数组了,具体编码如下:

/*** 普通数组转稀疏数组* * @param arr_普通数组* @return 稀疏数组*/
public static int[][] castSparseArray(int[][] arr) {// 原数组的总行数int row = arr.length;// 原数组的总列数int cloumn = arr[0].length;// 获取黑白子总数int sum = 0;for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length; j++) {if (arr[i][j] != 0) {sum++;}}}// 创建稀疏数组(sum+1 行表示 sum 个黑白子 + 1行规模)int[][] sparseArray = new int[sum + 1][3];// 第 1 行原二维数组的行、列、棋子总数sparseArray[0][0] = row;sparseArray[0][1] = cloumn;sparseArray[0][2] = sum;// 第 2 行开始存具体数据(每行都是一个棋子数据)int sparseRow = 0;for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length; j++) {if (arr[i][j] != 0) {sparseRow++;sparseArray[sparseRow][0] = i;sparseArray[sparseRow][1] = j;sparseArray[sparseRow][2] = arr[i][j];}}}return sparseArray;
}

【5】稀疏数组转二维数组

我们用稀疏数组保存数据,主要是为了节省磁盘空间,优化 IO 读写性能,但在最终复原棋盘的时候,我们还是需要将稀疏数组的数据转化为原普通二维数组数据,那么我们又将如何通过编码的方式去实现稀疏数组转二维数组呢?对应编码如下:

/*** 稀疏数组转普通数组* * @param sparseArr_稀疏数组* @return 普通二维数组*/
public static int[][] castToArray(int[][] sparseArr) {// 获取稀疏数组第 1 行(记录了原数组的总行数和总列数)int[] rowFirst = sparseArr[0];// 初始化数组(棋盘)int row = rowFirst[0];int column = rowFirst[1];int[][] arr = new int[row][column];// 初始化数据(黑白子)for (int i = 1; i < sparseArr.length; i++) {int[] sparseRow = sparseArr[i];arr[sparseRow[0]][sparseRow[1]] = sparseRow[2];}return arr;
}

这样,我们就可以将稀疏数组还原为普通数组了。

【总结】

在存储数组数据的时候,我们如果存在许多默认值的数据,不妨用稀疏数组来进行存储,这样数据相对来说就会瘦小很多,不但可以节省磁盘空间,还可以优化磁盘读写时性能。

最后附上相关的整段代码:

/*** 二维数组与稀疏数组* * @author ZhangYuanqiang* @since 2021年5月13日*/
public class SparseArrayTest {public static void main(String[] args) {// 用二维数组保存棋盘int[][] arr = saveChess();// 打印二维数组print(arr);// 将二维数组转化为稀疏数组int[][] sparseArr = castSparseArray(arr);// 打印稀疏数组print(sparseArr);// 稀疏数组转二位数组int[][] arr2 = castToArray(sparseArr);print(arr2);}/*** 打印普通数组*/public static void print(int[][] arr) {for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr[i].length; j++) {System.out.print(arr[i][j] + "\t");}System.out.println();}System.out.println("--------------------------------------");}/*** 将棋盘数据保存为二维数组*/public static int[][] saveChess() {// 初始化棋盘(大小为 15 * 15)int[][] arr = new int[15][15];// 保存白子(用1表示)arr[5][5] = 1;arr[7][5] = 1;arr[6][7] = 1;// 保存黑子(用2表示)arr[6][6] = 2;arr[7][6] = 2;arr[8][6] = 2;arr[7][7] = 2;return arr;}/*** 普通数组转稀疏数组* * @param arr_普通数组* @return 稀疏数组*/public static int[][] castSparseArray(int[][] arr) {// 原数组的总行数int row = arr.length;// 原数组的总列数int cloumn = arr[0].length;// 获取黑白子总数int sum = 0;for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length; j++) {if (arr[i][j] != 0) {sum++;}}}// 创建稀疏数组(sum+1 行表示 sum 个黑白子 + 1行规模)int[][] sparseArray = new int[sum + 1][3];// 第 1 行原二维数组的行、列、棋子总数sparseArray[0][0] = row;sparseArray[0][1] = cloumn;sparseArray[0][2] = sum;// 第 2 行开始存具体数据(每行都是一个棋子数据)int sparseRow = 0;for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr.length; j++) {if (arr[i][j] != 0) {sparseRow++;sparseArray[sparseRow][0] = i;sparseArray[sparseRow][1] = j;sparseArray[sparseRow][2] = arr[i][j];}}}return sparseArray;}/*** 稀疏数组转普通数组* * @param sparseArr_稀疏数组* @return 普通二维数组*/public static int[][] castToArray(int[][] sparseArr) {// 获取稀疏数组第 1 行(记录了原数组的总行数和总列数)int[] rowFirst = sparseArr[0];// 初始化数组(棋盘)int row = rowFirst[0];int column = rowFirst[1];int[][] arr = new int[row][column];// 初始化数据(黑白子)for (int i = 1; i < sparseArr.length; i++) {int[] sparseRow = sparseArr[i];arr[sparseRow[0]][sparseRow[1]] = sparseRow[2];}return arr;}
}

什么是稀疏数组?稀疏数组详解相关推荐

  1. ES5和ES6数组遍历方法详解

    ES5和ES6数组遍历方法详解 在ES5中常用的10种数组遍历方法: 1.原始的for循环语句 2.Array.prototype.forEach数组对象内置方法 3.Array.prototype. ...

  2. 旋转排序数组系列题详解

    旋转排序数组系列题详解 文章目录 旋转排序数组系列题详解 一.问题描述:旋转数组的最小数字 二.分析:二分查找 三.代码 四.问题描述:寻找旋转排序数组中的最小值 五.分析:二分搜索 六.代码 七.问 ...

  3. c语言char数组和short数组的区别,详解C语言中Char型指针数组与字符数组的区别

    详解C语言中Char型指针数组与字符数组的区别 详解C语言中Char型指针数组与字符数组的区别 1.char 类型的指针数组:每个元素都指向一个字符串,指向可以改变 char *name[3] = { ...

  4. C语言 字符数组 和 字符串 详解

    C语言 字符数组 和 字符串 详解 用来存放字符的数组称为字符数组,例如: char a[10]; //一维字符数组 char b[5][10]; //二维字符数组 char c[20]={'c', ...

  5. pythonprint字节按照16进制输出_对python以16进制打印字节数组的方法详解

    对python以16进制打印字节数组的方法详解 一.问题描述 如果直接用print打印bytes的话,有时候会直接显示ascii对应的字符,看起来很蛋疼. 二.运行效果 上面一行是直接用print打印 ...

  6. linux jq 遍历数组,jquery 遍历数组 each 方法详解

    JQuery拿取对象的方式 $('#id') :通过元素的id $('tagName') : 通过元素的标签名 $('tagName tagName') : 通过元素的标签名,eg: $('ul li ...

  7. java生成字符串数组_Java 生成随机字符串数组的实例详解

    Java 生成随机字符串数组的实例详解 利用Collections.sort()方法对泛型为String的List 进行排序.具体要求: 1.创建完List之后,往其中添加十条随机字符串 2.每条字符 ...

  8. C语言数组之间赋值详解

    数组之间的赋值,C语言数组之间赋值详解 (biancheng.net)

  9. python的对象数组_Python当中的array数组对象实例详解

    计算机为数组分配一段连续的内存,从而支持对数组随机访问: 由于项的地址在编号上是连续的,数组某一项的地址可以通过将两个值相加得出,即将数组的基本地址和项的偏移地址相加. 数组的基本地址就是数组的第一项 ...

  10. jQuery数组处理完全详解

    jQuery的数组处理.便捷.功能齐全.最近的项目中用到的比较多,深感实用,一步到位的封装了很多原生JavaScript数组不能企及的功能.最近时间紧迫,今天抽了些时间回过头来看jQuery中文文档中 ...

最新文章

  1. Dev-C++ v5.11
  2. 翻译职称计算机能力,2018年职称计算机word2003考点辅导:用好Office2003中的翻译功能...
  3. JAVA笔记(十四)
  4. CSS——Fonts(字体)
  5. Java校招笔试题-Java基础部分(二)
  6. linux系统win,Windows10安装运行linux系统的方法
  7. 自然语言处理基本概念及基础工具
  8. java定义vip顾客继承顾客_Java初级教频教程 - JavaSE - Java - 私塾在线 - 只做精品视频课程服务...
  9. 【07】processing-字体(中文)
  10. Java打印正三角形
  11. oracle PL/SQL 这些查询结果不可更新,请包括ROWID或使用SELECT ...FOR UPDATE 获得可
  12. 工具使用,PS隐藏技能—对称绘画
  13. 2006-01-23,科比-布莱恩特得了81分
  14. 伊诺ET-33夹式校(音器吉他/贝司/小提琴/尤克里里 使用
  15. 从飞猪智能酒店到优酷视频,探索阿里智能研发协同流程
  16. 课堂教学评价的主要内容
  17. Yelp Dataset(Yelp业务-评论-用户数据集)
  18. 屏幕录像功能技术探索及分享
  19. SQL--乱七八糟问题
  20. C#/Unity不允许发送UDP到255.255.255.255的解决方法

热门文章

  1. Node基础——认识Node
  2. OneHotEncoder独热编码
  3. python调用谷歌翻译Googletrans接口
  4. 中文键盘 linux,键盘和中文输入 教程
  5. Logstash报错:[ERROR][logstash.agent ] Failed to execute action {...
  6. python 抛出异常记录
  7. gmail+mtalk配合打免费网络电话。
  8. Multisim电路仿真-验证KCL和KVL
  9. Zabbix 3.0 版本企业微信群机器人报警
  10. 代码: 0x80131500:应用商店打不开