相关概念
什么是稀疏矩阵?
稀疏矩阵是指矩阵中的大部分元素为0的矩阵。
什么是稀疏数组?
稀疏数组是一种用于压缩稀疏矩阵的数据结构(二维数组)。
应用场景
概念中提到的稀疏数组可以压缩稀疏矩阵,因此当我们面临一个二维数组的的大部分元素为0(根据实际情况也可以是其它值)时,就可以使用稀疏数组来对该二维数组进行压缩。
围棋比赛就是一个实际的应用场景。我们可以把棋盘与已经下落的棋子抽象为二维数组白字和黑子为二维数组中的元素,值分别为0和1,未落子的位置同为二维数组的元素,值为0。一般情况下我们可以用与棋盘”等大“的二维数组将每个有子或无子的位置元素记录下来,但使用稀疏数组的话我们只需要记录已经落子的位置元素。
稀疏数组的基本原理
稀疏数组的主要思想是不保存元素组中默认的元素,默认元素为原数组中数量较大的元素,其他元素则为需要保存的有效元素。
原数组向稀疏数组转化的实现并不难,重要的就是理解稀疏数组的压缩原理。
通常情况下,稀疏数组的构成如下:
- 稀疏数组的大小根据原数组来确定,稀疏数组的行大小即为原数组有效元素的数量+1;列大小固定3列。
- 每列分别表示原数组有效元素所在的行、列、有效元素值。
- 需要注意的是,稀疏数组的第一行比较特殊,其存储的分别是原数组的行总数、列总数、原数组有效元素总数。
简单实现
相信了解以上内容后我们能够通过代码实现二维数组压缩为稀疏数组,也能由稀疏数组还原二维数组,以下是对其的简单实现(一些异常的处理等工作并不完整,各位可以自行完善):
/**
*对一个11×11的棋盘进行数据的存储,使用稀疏矩阵
*/
public class SparseArrays {
public static void main(String[] args) throws IOException {
// 利用稀疏数组将存储棋盘数据的数组转为稀疏数组
int[][] chessboard = new int[11][11]; //创建棋盘
// 1、2分别表示白子、黑子
chessboard[2][2] = 1;
chessboard[3][4] = 1;
chessboard[4][4] = 1;
chessboard[2][5] = 2;
chessboard[10][5] = 2;
chessboard[7][10] = 1;
// 原数组
System.out.println("============原数组============");
printArray(chessboard);
System.out.println();
System.out.println("=============稀疏数组===========");
int[][] sparseArray = getSparseArray(chessboard);
printArray(sparseArray);
System.out.println();
System.out.println("============直接恢复原数组===========");
int[][] array = getArray(sparseArray);
printArray(array);
System.out.println();
System.out.println("===============写入并读取文件数据=============");
saveMsg(sparseArray);
int[][] oldChessboard = readOut();
printArray(oldChessboard);
System.out.println();
}
// 二维数组转为稀疏数组
public static int[][] getSparseArray(int[][] chessboard) throws IOException {
// 统计原数组的有效元素总数
int sum = 0;
for (int[] ints : chessboard) {
for (int anInt : ints) {
if (anInt != 0) {
sum++;
}
}
}
// 创建的稀疏数组有3列,分别表示原数组有效值所在的行、列、值。只有第一行比较特殊,存储的是元素组的行总数、列总数、有效元素的总数
int[][] sparseArray = new int[sum + 1][3];
sparseArray[0][0] = chessboard.length;
sparseArray[0][1] = chessboard[0].length;
sparseArray[0][2] = sum;
// 稀疏数组赋值
int count = 0;
for (int i = 0; i < chessboard.length; i++) {
for (int j = 0; j < chessboard[0].length; j++) {
if (chessboard[i][j] != 0) {
count++;
sparseArray[count][0] = i;
sparseArray[count][1] = j;
sparseArray[count][2] = chessboard[i][j];
}
}
}
return sparseArray;
}
// 稀疏数组转二维数组
public static int[][] getArray(int[][] sparseArray) {
// 创建原数组
int[][] arr = new int[sparseArray[0][0]][sparseArray[0][1]];
for (int i = 1; i < sparseArray.length; i++) {
arr[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
}
return arr;
}
// 打印二维数组
public static void printArray(int[][] array) {
for (int[] ints : array) {
for (int anInt : ints) {
System.out.printf("%d ", anInt);
}
System.out.println();
}
}
// 保存数据
public static void saveMsg(int[][] arr) {
try (FileWriter fileWriter = new FileWriter("file.txt")) {
for (int[] ints : arr) {
for (int anInt : ints) {
fileWriter.write(anInt + " ");
}
fileWriter.write("\n");
}
} catch (Exception e) {
System.out.println("保存出错");
}
}
// 读出被保存数据
public static int[][] readOut() throws IOException {
// 读取数据
ArrayList<Integer> items = new ArrayList<>(); //存储读取的数据
try (FileReader fileReader = new FileReader("file.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader)) {
String temp = "";
while ((temp = bufferedReader.readLine()) != null) {
String[] s = temp.split(" ");
Arrays.stream(s).forEach(number -> items.add(Integer.valueOf(number)));
}
}
// 恢复原数组
int[][] chessboard = new int[items.size() / 3][3];
for (int i = 0; i < chessboard.length; i++) {
for (int j = 0; j < chessboard[0].length; j++) {
chessboard[i][j] = items.get(i * 3 + j);
}
}
return getArray(chessboard);
}
}```