更多内容参考:https://www.yuque.com/zhangshuaiyin/algorithms
1. 实际需求
编写的五子棋程序中,有存盘退出和续上盘的功能。
分析问题:
因为该二维数组的很多值是默认值 0, 因此记录了 很多没有意义的数据。
这个时候就可以使用稀疏数组来压缩二维数组。
2. 基本介绍
当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法是:
- 记录数组 一共有几行几列,有多少个有效值
- 把具有不同值的元素的行、列及值记录在一个小规模的数组中,从而缩小程序的规模
示例:二维数组和对应的稀疏数组
3. 应用实例
分析
使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等);
把稀疏数组存盘,并且可以重新恢复原来的二维数组数组
思路
二维数组转稀疏数组的思路:
- 遍历原始的二维数组,得到有效数据的个数
sum
- 根据 sum 就可以创建稀疏数组
sparseArr int[sum + 1] [3]
- 将二维数组的有效数据数据存入到稀疏数组
稀疏数组转原始的二维数组的思路:
- 先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组,比如上面的
chessArr = int [11][11]
- 再读取稀疏数组后几行的数据,并赋给原始的二维数组即可.
实现
package com.zsy.datastructure.sparsearray;
/**
* 使用稀疏数组,来保留类似前面的二维数组棋盘(11*11)
* 把稀疏数组存盘,并且可以重新恢复原来的二维数组数组
*
* @author zhangshuaiyin
*/
public class Main {
/**
* 初始二维数组棋盘大小
*/
private final static int ROW = 11;
private final static int COL = 11;
public static void main(String[] args) {
/* *****************************二维数组转稀疏数组******************************** */
System.out.println("*****************************二维数组转稀疏数组********************************");
// 初始化棋盘二维数组, 其中0代表空棋盘,1代表黑子,2代表蓝子
int[][] chessArray = new int[ROW][COL];
chessArray[0][1] = 1;
chessArray[1][3] = 2;
chessArray[2][5] = 1;
// 输出二维数组棋盘
System.out.println("二维数组棋盘:");
printChessArray(chessArray);
// 2. 获取二维数组有效数据个数(棋盘中棋子个数)
int sum = getChessSum(chessArray);
System.out.println("棋盘中有效数据个数:" + sum);
// 3. 初始化稀疏数组 稀疏数组行数为有效棋子数加1, 列数为3
int[][] sparseArray = new int[sum + 1][3];
// 稀疏数组第一行三个数据分别代表:棋盘行数 棋盘列数 棋子个数
sparseArray[0][0] = ROW;
sparseArray[0][1] = COL;
sparseArray[0][2] = sum;
// 4. 将二维数组数据保存到稀疏数组
chessToSparse(chessArray, sparseArray);
// 输出稀疏数组
System.out.println("稀疏数组:");
printSparseArray(sparseArray);
/* *****************************稀疏数组转二维数组******************************** */
System.out.println("*****************************稀疏数组转二维数组********************************");
chessArray = sparseToChess(sparseArray);
// 输出二维数组棋盘
System.out.println("恢复的二维数组棋盘:");
printChessArray(chessArray);
}
/**
* 稀疏数组还原二维数组棋盘
*
* @param sparseArray 稀疏数组
* @return 棋盘
*/
private static int[][] sparseToChess(int[][] sparseArray) {
// 1. 读取稀疏数组第一行,获取棋盘信息
int row = sparseArray[0][0];
int col = sparseArray[0][1];
int[][] chessArray = new int[row][col];
// 2. 读取稀疏数组其余行,获取棋子信息
for (int i = 1; i < sparseArray.length; i++) {
chessArray[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
}
return chessArray;
}
/**
* 输出二维数组棋盘
*
* @param chessArray 棋盘数组
*/
public static void printChessArray(int[][] chessArray) {
for (int[] rows : chessArray) {
for (int item : rows) {
System.out.printf("%d\t", item);
}
System.out.println();
}
}
/**
* 获取棋盘中棋子个数
*
* @param chessArray 棋盘数组
* @return 棋子个数
*/
public static int getChessSum(int[][] chessArray) {
int sum = 0;
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
if (chessArray[i][j] != 0) {
sum++;
}
}
}
return sum;
}
/**
* 输出稀疏数组
*
* @param sparseArray 稀疏数组
*/
public static void printSparseArray(int[][] sparseArray) {
for (int[] rows : sparseArray) {
for (int item : rows) {
System.out.printf("%d\t", item);
}
System.out.println();
}
}
/**
* 二维数组数据保存到稀疏数组中
* line:稀疏数组的行号
* <p>
* 稀疏数组数据保存结构:
* 第一行:棋盘行数 棋盘列数 棋子个数
* 第二行:棋子行数 棋子列数 棋子值
* ......
*
* @param chessArray 棋盘数组
* @param sparseArray 稀疏数组
*/
public static void chessToSparse(int[][] chessArray, int[][] sparseArray) {
// 稀疏数组行号
int line = 0;
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
if (chessArray[i][j] != 0) {
line++;
sparseArray[line][0] = i;
sparseArray[line][1] = j;
sparseArray[line][2] = chessArray[i][j];
}
}
}
}
}
4. 实践练习
要求:
- 在前面的基础上,将稀疏数组保存到磁盘上,比如 map.data
- 恢复原来的数组时,读取 map.data 进行恢复
/**
* 把稀疏数组保存到文件中
*
* @param sparseArray 稀疏数组
*/
public static void sparseToFile(int[][] sparseArray) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter("map.data"))) {
for (
int[] rows : sparseArray) {
for (int item : rows) {
writer.write(item + "");
writer.write("\t");
}
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 从文件中读取到稀疏数组
*
* @return sparseArray 稀疏数组
*/
public static int[][] fileToSparse() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("map.data"));
int count = (int) reader.lines().count();
reader = new BufferedReader(new FileReader("map.data"));
int[][] sparseArray = new int[count][3];
String tempString = null;
int num = 0;
while ((tempString = reader.readLine()) != null) {
String[] split = tempString.split("\t");
sparseArray[num][0] = Integer.parseInt(split[0]);
sparseArray[num][1] = Integer.parseInt(split[1]);
sparseArray[num][2] = Integer.parseInt(split[2]);
num ++;
}
return sparseArray;
} catch (IOException e) {
e.printStackTrace();
return new int[0][];
}
}