稀疏数组Sparse Array
一、实际需求
五子棋是一种双人对弈的策略性棋类游戏,在我们用Java编写五子棋程序时,我们会设法实现存盘退出和续上盘这样的一些功能。存盘退出,实际上就是要求我们对当前的棋盘进行记录并且写入到文件里面,这样选择续上盘的功能时才能从文件当中读档,恢复到上次保存的棋局当中。
我们在存储如左图所示的棋盘时,通常会选择一个二维数组,如右图所示。但是在大多数情况下该二维数组的很多值是默认值0,这样在无形当中就记录了很多没有意义的数据。这时可以采用稀疏数组,减少数据的存储量,设法不去存储默认值。
二、基本介绍
当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法是:
- 记录二维数组一共有几行几列,有多少个不同位置的元素;
- 把不同的元素的行列及值记录在一个小规模的数组(即稀疏数组)中,从而缩小程序的规模。
下面简单地举例说明:
左图是一个二维数组的矩阵表示,右图是将二维数组转换成的稀疏数组。
三、应用实例
- 使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等)
- 把稀疏数组存盘,并且可以重新恢复原来的二维数组
- 整体思路分析
4. 代码实现
四、课后练习
要求
- 在前面的基础上,将稀疏数组保存到磁盘上,比如map.data
- 恢复原来的数组时,读取map.data进行恢复
代码
package linerStructures;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class sparseArray {
public static void main(String args[]){
int chessArray1[][]=new int [11][11]; //创建一个二维数组表示初始棋盘
chessArray1[1][2]=1; //用 1 表示棋盘上的黑子
chessArray1[2][3]=2; //用 2 表示棋盘上的蓝子
//输出棋盘
// for(int[] row:chessArray1){
// for(int data:row){
// System.out.printf("%d\t",data);
// }
// System.out.println();
// }
//将二维数组 转 稀疏数组
//1、 先遍历 二维数组,得到非 0 数据的个数,用于创建 稀疏数组
// 二维数组 转 稀疏数组的思路
// 1) 遍历原始的二维数组,得到有效数据的个数 sum
// 2) 根据sum 就可以创建 稀疏数组 sparseArr int[sum + 1] [3]
// 3) 将二维数组的有效数据数据存入到 稀疏数组
int num=0; //记录数据的个数
for(int i=0;i<chessArray1.length;i++){
for(int j=0;j<chessArray1[0].length;j++){
if(chessArray1[i][j]!=0){
num++;
}
}
}
//2、 接着创建一个 稀疏数组
int sparseArray1[][]=new int [num+1][3]; //建立一个num+1行,2列的 稀疏数组
sparseArray1[0][0]=11;//第一行记录 二维数组 的行列以及数据的个数
sparseArray1[0][1]=11;
sparseArray1[0][2]=num;
//3、 取得非 0 位置的值
int count=0;
for(int i=0;i<chessArray1.length;i++){
for(int j=0;j<chessArray1[0].length;j++){
if(chessArray1[i][j]!=0){
sparseArray1[count+1][0]=i;
sparseArray1[count+1][1]=j;
sparseArray1[count+1][2]=chessArray1[i][j];
count++;
}
}
}
//4、 输出 稀疏数组
// for(int i=0;i<sparseArray1.length;i++){
// System.out.printf("%d\t%d\t%d\n",sparseArray1[i][0],sparseArray1[i][1],sparseArray1[i][2]);
// }
//5、 将 稀疏数组 恢复成 二维数组
// 稀疏数组转原始的二维数组的思路
// 1) 先读取稀疏数组的第一行,根据第一行的数据,
// 创建原始的二维数组,比如上面的 chessArr2 = int [11][11]
// 2) 在读取稀疏数组后几行的数据,并赋给 原始的二维数组 即可.
int row=sparseArray1[0][0],col=sparseArray1[0][1];
int chessArray2[][]=new int[row][col]; //重新创建一个二维数组
for(int i=1;i<sparseArray1.length;i++){
//稀疏数组每一行的第一列是二维数组里的行号,第二列是列号,第三列是数据
chessArray2[sparseArray1[i][0]][sparseArray1[i][1]]=sparseArray1[i][2];
}
// for(int[] r:chessArray2){
// for(int data:r){
// System.out.printf("%d\t",data);
// }
// System.out.println();
// }
//6、 练习题 :将稀疏数组输出到文件当中 然后再从文件中读取并恢复二维数组
try{
String string=new String("sparseArray.txt");
FileWriter fw=new FileWriter(string);
for(int[] row1:sparseArray1) {
for (int data : row1) {
fw.write(data+"\t");
}
}
fw.close();
}catch(IOException e){
e.printStackTrace();
}
try {
List<Integer> l=new ArrayList<>();
String string=new String("sparseArray.txt");
File f=new File(string);
BufferedReader br=new BufferedReader(new FileReader(f));
// String s=br.readLine();
// System.out.println(s);
// String[] numbers=s.split("\t");
// System.out.println(numbers[3]); //用来检查错误的代码
String s=null;
while((s=br.readLine())!=null){
String[] sn=s.split("\t");
for(String sc:sn) {
int i = Integer.parseInt(sc);
l.add(i);
}
}
int r=l.get(0),c=l.get(1);
int chessArray3[][]=new int[r][c]; //重新创建一个二维数组
for(int i=3;i<l.size();i++){
//稀疏数组每一行的第一列是二维数组里的行号,第二列是列号,第三列是数据
if(i%3==0) chessArray3[l.get(i)][l.get(i+1)]=l.get(i+2);
}
for(int[] three:chessArray3) {
for (int data : three) {
System.out.printf("%d\t", data);
}
System.out.println();
}
br.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
笔记
split()函数报错:读取文件的时候,分割从文件当中读到的一整行数据,忘记写文件的时候用的分隔符是‘\t’。所以一直在用空格去分割,自然得不到正确的结果。
参考资料
[1] 尚硅谷-韩顺平 Java数据结构和算法课件