稀疏数组的应用场景:
稀疏数组的核心概念是在实际的应用场景中使用合理的数据结构对数据进行存储,稀疏数组最经典的举例想必就是五子棋游戏的存/读盘操作。但用户有存盘需求时肯定是正在游戏中。此时肯定会有很多的无用数据,如果直接存盘肯定会对IO和存储造成压力。此时就需要将棋盘的二维数组转化为稀疏数组进行存盘,减小IO和存储压力。
稀疏数组其实也是二维数组,但是将普通二维数组变为没有无用数据的二维数组。
以五子棋盘游戏为例
普通存储棋盘的二维数组:
有很多无用的没有棋子的占位0
二维数组转化成稀疏数组:
彻底排除了无用的占位0,行数随所下的棋子增加,列数始终是3列,在进行存盘操作时减少磁盘IO和存储的压力。
稀疏数组含义:
首行数据存储的是棋盘总的行列和棋盘上现有的棋子数量。其余行存的是每个棋子所在的行列及是什么棋子。
二维数组转稀疏数组的实现:
/**
* 稀疏数组
*/
public class SparseArray {
//模拟五子棋游戏,创建二维数组记录棋盘,然后用稀疏数组进行优化,减小占用空间。并加上存、读盘操作。
public static void main(String[] args) {
int[][] ints = buildDoubleArray();
int[][] sparseArray = toSparseArray(ints);
writeToFile(sparseArray);
readFromFile(3);
sparseArrayToDoubleArray(sparseArray);
}
//第一步,创建二维数组模拟五子棋盘
private static int[][] buildDoubleArray() {
//创建原始的二维数组,11*11
//0:没有棋子落下,1:黑子,2:白子
int chessArr1[][] = new int[11][11];
//int[][] chess = new int[10][10];
//棋子落下的位置
chessArr1[1][2] = 1;
chessArr1[2][3] = 2;
/*for (int[] row : chessArr1) {
for (int item : row) {
System.out.printf("%d\t",item);
}
System.out.println();
}*/
return chessArr1;
}
//第二步,将二维数组转为稀疏数组。
private static int[][] toSparseArray(int[][] chessArray) {
//棋子个数
int chessSum = 0;
//总行数
int rowSum = 0;
//总列数
int colSum = 0;
/**
* 得到创建稀疏数组要用到的行列数据
*/
for (int i = 0; i<chessArray.length;i++) {
//计算总行数
rowSum ++;
//得到一行的数据
int[] col = chessArray[i];
for (int j = 0; j<col.length;j++) {
//计算总列数
if (i==0) {
colSum ++;
}
//得到一行中的具体数据
int data = col[j];
if (data != 0) {
chessSum ++;
}
}
}
//初始化稀疏数组
//稀疏数组存放格式:共3列,第一列是row,第二列是col,第三列是val。第一行存的是二维数组总的行列数和有意义的元素个数。其余行存的是非0元素所在的行列。
int sparseArray[][] = new int[chessSum+1][3];
//创建稀疏数组的第一行数据:
sparseArray[0][0] = rowSum;
sparseArray[0][1] = colSum;
sparseArray[0][2] = chessSum;
//创建稀疏数组的剩余行非0元素所在的行列(不用集合实现)
//记录第几个非0元素(用在声明稀疏数组的行)
int sparseColCount = 0;
for (int i = 0;i < chessArray.length;i++) {
int[] col = chessArray[i];
for (int j = 0;j < col.length;j++){
int data = col[j];
if (data != 0) {
sparseColCount++;
sparseArray[sparseColCount][0] = i;
sparseArray[sparseColCount][1] = j;
sparseArray[sparseColCount][2] = data;
}
}
}
/*for (int[] row:sparseArray) {
for (int data:row) {
System.out.printf("%d\t",data);
}
System.out.println();
}*/
return sparseArray;
//对参数中的二维数组进行效果展示:
/*for (int i = 0; i<chessArray.length;i++) {
int[] col = chessArray[i];
for (int j = 0; j<col.length;j++) {
int data = col[j];
if (data != 0) {
chessSum ++;
}
System.out.printf("%d\t",data);
}
System.out.println();
}*/
}
/**
* 将稀疏数组还原为二维数组
* @param sparseArray
* @return
*/
private static int[][] sparseArrayToDoubleArray(int[][] sparseArray) {
//初始化二维数组
int[][] doubleArray = new int[sparseArray[0][0]][sparseArray[0][1]];
//得到二维数组中非0元素的坐标及元素值(直接排除稀疏数组的第一行总体表格数据)
for (int i = 1; i < sparseArray.length; i++) {
int[] row = sparseArray[i];
doubleArray[row[0]][row[1]] = row[2];
}
/**
* 查看效果
*/
for (int[] row:doubleArray) {
for (int data:row) {
System.out.printf("%d\t",data);
}
System.out.println();
}
return null;
}
/**
* 将二维数组保存在文件
* @param sparseArray
*/
private static void writeToFile(int[][] sparseArray) {
File file = new File("F:\\sparseArray.txt");
if (file.exists()) {
file.delete();
}
DataOutputStream out = null;
try {
out = new DataOutputStream(new FileOutputStream(file));
for (int[] row : sparseArray) {
for (int data : row) {
out.writeInt(data);
}
}
out.flush();
out.close();
System.out.println("稀疏数组已写入文件");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 从文件中读取稀疏数组
* @param sumRow
* @return
*/
private static int[][] readFromFile(int sumRow) {
File file = new File("F:\\sparseArray.txt");
int[][] sparseArray = new int[sumRow][3];
try {
DataInputStream in = new DataInputStream(new FileInputStream(file));
for (int i = 0;i<sumRow;i++) {
sparseArray[i][0] = in.readInt();
sparseArray[i][1] = in.readInt();
sparseArray[i][2] = in.readInt();
}
} catch (IOException e) {
e.printStackTrace();
}
for (int[] row:sparseArray) {
for (int data:row) {
System.out.printf("%d\t",data);
}
System.out.println();
}
return sparseArray;
}
}