一、前言
记录时间 [2024-05-06]
系列文章简摘:
Java 笔记 01:Java 概述,MarkDown 常用语法整理
Java 笔记 02:Java 开发环境的搭建,IDEA / Notepad++ / JDK 安装及环境配置,编写第一个 Java 程序
Java 笔记 11:Java 方法相关内容,方法的设计原则,以及方法的定义和调用
Java 笔记 13:Java 数组内容,数组的声明、创建、初始化、赋值等,以及内存分析
更多 Java 相关文章,请参考上面专栏哦。
本文是对 Java 数组相关内容的补充——稀疏数组,以棋盘存储的案例,分析如何将一个普通二维数组压缩成稀疏数组。
二、稀疏数组概述
稀疏数组是一种用来表示大多数元素都具有相同值的二维数组的数据结构。
通常,稀疏数组会将大多数元素设置为默认值,然后只存储非默认值的元素及其位置信息。这种表示方法可以节省内存空间,特别是当大多数元素具有相同值时。
稀疏数组通常用于处理稀疏矩阵(大多数元素为零的矩阵)、表示地图中的稀疏区域、存储棋盘上的棋子位置等场景。
稀疏数组通常包含三个字段:
- 原始数组的行数
- 原始数组的列数
- 非默认值的个数及其位置信息
三、处理方式
- 记录数组一共有几行几列,有多少个不同值;
- 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模。
例如,有这样一个棋盘,我们用二维数组表示:
这是一个 11 行 11 列的棋盘,其中,0 表示空,1 表示黑子,2 表示白子。不难发现,这个棋盘中有一枚黑子(行一列二),一枚白子(行二列三)。
注意:数组下标索引从 0 开始。
# 这是一个 11 行 11 列的棋盘
# 其中,0 表示空,1 表示黑子,2 表示白子
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
0 0 0 0 0 0 0 0 0 0 0
把它压缩成稀疏数组后:
# 第一行:棋盘大小为 11*11,棋子个数为 2 枚
# 第二行:行一列二有一枚黑子
# 第三行:行二列三有一枚白子
11 11 2
1 2 1
2 3 2
四、编写数组存放棋盘
我们在 Java 中分别使用二维数组和稀疏数组来存放这两个棋盘。
二维数组
二维数组在创建时如果没有赋值,数组元素默认赋值为 0。
定义一个普通的二维数组用来存放棋盘:
/*
一个普通的二维数组
用来存放棋盘,11*11,空 0,黑子 1,白子 2
*/
public static int[][] chessPlate() {
// 定义二维数组,表示一个棋盘
int[][] plate = new int[11][11];
// 黑子 行 1 竖 2;白子 行 2 竖 3
plate[1][2] = 1;
plate[2][3] = 2;
// 返回棋盘
return plate;
}
稀疏数组
在稀疏数组的第一行(索引为 0)中,记录了棋盘的行列数,以及棋子的总数。
每一枚棋子都记录了坐标和类别,比如,有一枚黑子(行一列二),一枚白子(行二列三)。
定义一个稀疏数组用来存放棋盘:
/*
一个稀疏数组
用来存放棋盘,11*11,空 0,黑子 1,白子 2
*/
public static int[][] chessPlateZip() {
// 定义稀疏数组,表示一个棋盘
// 有两个非 0 元素
int[][] plate = new int[3][3];
// 11*11 2 枚棋子
plate[0][0] = 11;
plate[0][1] = 11;
plate[0][2] = 2;
// 黑子 行 1 竖 2;白子 行 2 竖 3
plate[1][0] = 1;
plate[1][1] = 2;
plate[1][2] = 1;
plate[2][0] = 2;
plate[2][1] = 3;
plate[2][2] = 2;
return plate;
}
五、压缩还原
普通二维数组和稀疏数组之间可以互相转换。
稀疏数组本质上也是一个二维数组,但它相比于普通二维数组更轻量,减少了存储空间。
压缩为稀疏数组
我们把一个符合要求的普通二维数组压缩为稀疏数组。
这个要求,主要指的是有很多重复的元素。
也就是压缩棋盘:
// 压缩成稀疏数组
public static int[][] zipToSparse(int[][] arrays) {
// 遍历二维数组获取非 0 值
int sum = 0;
for (int[] array : arrays) {
for (int i : array) {
if (i != 0) {
sum++;
}
}
}
int[][] result = new int[sum+1][3];
int count = 0;
// 记录棋盘行列数
result[0][0] = arrays.length;
result[0][1] = arrays[0].length;
// 记录棋子个数
result[0][2] = sum;
for (int i = 0; i < arrays.length; i++) {
for (int j = 0; j < arrays[i].length; j++) {
if (arrays[i][j] != 0) {
count++;
result[count][0] = i;
result[count][1] = j;
result[count][2] = arrays[i][j];
}
}
}
// 返回压缩后的稀疏数组
return result;
}
还原为二维数组
被压缩后的稀疏数组,可以还原为二维数组。
- 根据稀疏数组的第一行,确定棋盘的行列。
- 根据稀疏数组的长度,确定棋子的数量。
- 根据后面的每一行,确定棋子的坐标和类别。
// 解压缩为二维数组
public static int[][] turnToArrays(int[][] arrays) {
// 根据稀疏数组,确定棋盘行列
int[][] resultArrays = new int[arrays[0][0]][arrays[0][1]];
// 赋值元素,确定棋子的坐标和类别
for (int i = 1; i <= arrays[0][2]; i++) {
resultArrays[arrays[i][0]][arrays[i][1]] = arrays[i][2];
}
return resultArrays;
}
六、Main 方法测试
在 Main 方法中调用上述方法进行测试。
打印二维数组
打印二维数组用于查看压缩 / 还原后的棋盘。
// 打印二维数组
public static void printArrays(int[][] arrays) {
for (int[] array : arrays) {
for (int i : array) {
System.out.print(i + "\t");
}
System.out.println();
}
}
测试稀疏数组
由于是静态方法,所以可以直接调用。
public static void main(String[] args) {
// 打印这个棋盘
System.out.println("打印二维数组:");
printArrays(chessPlate());
// 打印压缩后的棋盘
System.out.println("打印稀疏数组:");
printArrays(chessPlateZip());
// 压缩这个棋盘
System.out.println("压缩这个棋盘:");
printArrays(zipToSparse(chessPlate()));
// 解压缩为二维数组
System.out.println("解压缩为普通棋盘:");
printArrays(turnToArrays(chessPlateZip()));
}
七、总结
本文是对 Java 数组相关内容的补充——稀疏数组,以棋盘存储的案例,分析如何将一个普通二维数组压缩成稀疏数组。
一些参考资料
狂神说 Java 零基础:https://www.bilibili.com/video/BV12J41137hu/
TIOBE 编程语言走势: https://www.tiobe.com/tiobe-index/
Typora 官网:https://www.typoraio.cn/
Oracle 官网:https://www.oracle.com/
Notepad++ 下载地址:https://notepad-plus.en.softonic.com/
IDEA 官网:https://www.jetbrains.com.cn/idea/
Java 开发手册:https://developer.aliyun.com/ebook/394
Java 8 帮助文档:https://docs.oracle.com/javase/8/docs/api/