前言
先看一下场景:
• 游戏开发:如存储大型游戏地图,如五子棋棋盘的状态,只需记录已落子位置;
• 图像处理:在图像矩阵中,大量像素可能为黑色(值为0)或其他单一颜色;
• 数据压缩:在科学计算、信号处理等领域,遇到大量接近零的浮点数矩阵时。
我们发现在使用数组记录数据的时候,会出现零的数据居多,非零数据较少的情况。进而导致直接存储整个数组会导致大量的空间浪费。
由此我们稀疏数组就可以解决这类问题
基本介绍
稀疏数组(Sparse Array)是一种特殊的数据结构,通常在编程中用于高效地存储和处理那些大部分元素为零(或具有相同默认值)的大规模数组,从而节省存储空间。
稀疏数组的结构
• 稀疏数组本质上是一个一维数组,其中每个元素是一个包含三个整数的元组(或数组、对象),分别对应原数组中的行索引、列索引以及该位置上的实际值。
• 稀疏数组通常以如下形式组织:
int[][] sparseArray = new int[n][3];
/* n 为非零元素数量 其中,
sparseArray[i]表示原数组中的第 i 个非零元素,
包含 [行索引, 列索引, 实际值]
*/
稀疏数组的创建过程
• 首先遍历原数组,统计所有非零或非默认值元素的数量和位置信息。
• 创建一个新的较小的二维数组(即稀疏数组),它的第一行通常用来存储原数组的维度(行数、列数以及非零元素的总数)。
• 将原数组中每个非零元素的位置信息(行、列)和对应的实际值存入稀疏数组的后续行中。
稀疏数组的还原
• 当需要恢复原数组时,可以根据稀疏数组的第一行信息重新构建一个足够大的二维数组,并根据稀疏数组中记录的位置和值信息填充非零元素。
应用实践
编写五子棋程序,存盘和继续上盘的功能
保存进稀疏数组
// 创建一个原始的二维数组 11 * 11
// 0表示没有棋子,1表示黑棋,2表示蓝棋
int[][] chessArr1 = new int[11][11];
chessArr1[1][2] = 1;
chessArr1[2][3] = 2;
chessArr1[4][5] = 2;
//1.先遍历二维数组
int sum_zero = 0;//用于记录非零个数
for (int i = 0; i < chessArr1.length; i++) {
for (int j = 0; j < chessArr1[i].length; j++) {
if (chessArr1[i][j] != 0) {
//2.通过计数器得到非零数值的个数
sum_zero++;
}
}
}
//3.创建对应的稀疏数组
int[][] sparseArr = new int[sum_zero + 1][3];
//给稀疏数组赋值(初始化第一行赋值)
sparseArr[0][0] = chessArr1.length;
sparseArr[0][1] = chessArr1[0].length;
sparseArr[0][2] = sum_zero;
//遍历二维数组,将非零的值存放到稀疏数组中
int count = 0;//用于记录是第几个非零数
for (int i = 0; i < chessArr1.length; i++) {
for (int j = 0; j < chessArr1[i].length; j++) {
if (chessArr1[i][j] != 0) {
count++;
sparseArr[count][0] = i;
sparseArr[count][1] = j;
sparseArr[count][2] = chessArr1[i][j];
}
}
}
//这里可以使用IO流进行保存
//我这里保存到文件中
//保存到文件sparseArr.txt中
//创建文件sparseArr.txt
BufferedWriter bw = null;
String file_path = "C:\\CJava\\data_structures\\temp_file\\sparseArr.txt";
try {
File file = new File(file_path);
bw = new BufferedWriter(new FileWriter(file));
for (int[] row : sparseArr) {
bw.write(row[0] + " " + row[1] + " " + row[2]);
//这里的空格为下面取出数据方便
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
下面从稀疏数组中取出数据放入到数组中
//将文件重新恢复为稀疏数组
String str = null;//取出数据放入
int row, col, num;
int counts = 1;//记录
int[][] sparseArr2 = new int[1024][3];
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file_path));
str = br.readLine();
String[] initialize = str.split(" ");
//通过空格进行区分
row = Integer.parseInt(initialize[0]);
col = Integer.parseInt(initialize[1]);
num = Integer.parseInt(initialize[2]);
sparseArr2 = new int[num + 1][3];
sparseArr2[0][0] = row;
sparseArr2[0][1] = col;
sparseArr2[0][2] = num;
while ((str = br.readLine()) != null) {
initialize = str.split(" ");
sparseArr2[counts][0] = Integer.parseInt(initialize[0]);
sparseArr2[counts][1] = Integer.parseInt(initialize[1]);
sparseArr2[counts][2] = Integer.parseInt(initialize[2]);
counts++;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//将稀疏数组恢复为二维数组
int[][] chessArr2 = new int[sparseArr2[0][0]][sparseArr2[0][1]];
for (int i = 1; i < sparseArr2.length; i++) {
chessArr2[sparseArr2[i][0]][sparseArr2[i][1]] = sparseArr2[i][2];
}//索引0超出长度0的界限
System.out.println("稀疏数组恢复后的二维数组为:");
for (int[] row2 : chessArr2) {
for (int col2 : row2) {
System.out.printf("%d\t", col2);
}
System.out.println();
}
}
总结
通过稀疏数组的储存方式,我们就可以有效地将原数组压缩存储,并且能够在需要时快速还原出来,大大降低了内存消耗,尤其是在处理大型矩阵或游戏地图等场景中非常实用。
有什么问题尽可以联系我,最后希望对各位佬有所帮助。