稀疏数组
1,稀疏数组的应用场景
进入正题之前可以先记一个单词:
- sparse 英[spɑːs]:adj. 稀少的; 稀疏的; 零落的
看一个稀疏数组相关的实际需求:

问:上图左侧是一个11*11的棋盘,目前棋盘上有两个棋子,一黑一蓝。如果要求把此时棋盘的状态保存起来(存盘退出),该如何做?
有人可能会认为可以使用如上图右侧的一个11×11的二维数组,把磁盘记录下来。其中1表示黑子,2表示蓝子,这固然可行,但不是最佳的方案。
实际上此处使用数据结构中的稀疏数组性能会更优秀。
要把棋盘转化为同样大小的二维数组并没有难度。但该二维数组会有很多值默认为0,记录了很多没有意义的数据。因此可以使用稀疏数组对二维数组进行压缩,从而实现优化。
二维数组的定义:
- 当一个数组中大部分元素为0,或者为同一个值 的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法:
- 记录数组一共有几行几列,有多少不同的值
- 把具有不同值的元素的行、列、值记录在一个小规模的数组中,从而缩小程序的规模,如下图:

上图中原数组记录42个数据,化为稀疏数组后只需要记录9*3=27个数据。
稀疏数组第一行数据表示:原始数组共几行,共几列,共几个非零值。
如上图的第一行表示,原始数组为6行7列共8个非零值。
稀疏数组除第一行外的每行(非首行)分别记录每一个非零值所在行列坐标和数据值大小。
如上图的第二行表示原始数组中第一行第四列的数据为22。
注意:行列均从0开始计数。
2,稀疏数组转换的思路分析

二维数组转稀疏数组思路:
- ①遍历原始的二维数组,得到有效数据个数sum。(知道有效数据个数可以知道稀疏数组的大小)
- ②根据sum创建稀疏数组,sparseArray int[sum+1] [3]。表示创建一个(sum+1)行3列的稀疏数组。(稀疏数组列数3是固定的,分别为行,列,值)
- ③将二维数组的有效数据存入到稀疏数组中
稀疏数组转二维数组思路:
- ①先读取稀疏数组的第一行,根据第一行的数据可以创建原始的二维数组;如上图是chessArr2=int[11] [11]
- ②再读取稀疏数组后几行的数据,并赋值给原始二维数组即可
以上过程再配合Java的IO操作(写入磁盘文件,文件读入内存)就可以实现类似下棋游戏过程中的“存盘退出”,“恢复上盘棋局” 的操作。
3,稀疏数组的代码实现(Java语言)
3.1,二维数组转化为稀疏数组:
将上述图中的二维数组转化为稀疏数组:
//创建一个原始的二维数组:11*11 //其中:0表示没有棋子;1表示黑子;2表示蓝子 int chessArray1[][]=new int[11][11]; chessArray1[1][2]=1; //表示第2行,第3列值为1 chessArray1[2][3]=2; //表示第3行,第4列值为2 //输出原始的二维数组查看 System.out.println("原始的二维数组如下:"); for (int[] row:chessArray1){
for (int data:row){
System.out.printf("%d\t",data); //格式化输出 } System.out.println(); //换行 } //将二维数组转化为稀疏数组 //第一步:遍历二维数组。计算有效数据个数(非0数据个数) int sum=0; for (int i=0;i<chessArray1.length;i++){
//遍历行。此时chessArray1.length为11 for (int j=0;j<11;j++){
//遍历列 if (chessArray1[i][j]!=0){
sum++; } } } System.out.println(sum); //2 //创建对应的稀疏数组 int sparseArray[][]=new int[sum+1][3]; //给稀疏数组赋值 sparseArray[0][0]=11; //稀疏数组第一行第一列为11 sparseArray[0][1]=11; sparseArray[0][2]=sum; //遍历二维数组,将非零值存放到sparseArray中 int count=0; //引入一个count用来记录是第几个非零数据 for (int i=0;i<chessArray1.length;i++){
for (int j=0;j<11;j++){
if (chessArray1[i][j]!=0){
count++; sparseArray[count][0]=i; //列很好确定,行需要找规律:第一个非0数据放在稀疏数组第二行,第二个非0数据放在稀疏数组第三行。。。因此引入一个count用来记录是第几个非零数据 sparseArray[count][1]=j; sparseArray[count][2]=chessArray1[i][j]; } } } //输出稀疏数组查看 System.out.println(); System.out.println("得到的稀疏数组为如下形式:"); for(int i=0;i<sparseArray.length;i++){
System.out.printf("%d\t%d\t%d\t\n",sparseArray[i][0],sparseArray[i][1],sparseArray[i][2]); // \t为制表符相当于tab,\n为换行 } System.out.println();
3.2,稀疏数组还原为二维数组
//将稀疏数组恢复成二维数组 //1,先读取稀疏数组的第一行,根据第一行数据初始化二维数组 int chessArray2[][]=new int[sparseArray[0][0]][sparseArray[0][1]]; //此时二维数组大小确定,内容全是0 //2,读取稀疏数组后几行数据,并赋给初始化好的二维数组 for (int i=1;i<sparseArray.length;i++){
//i=1表示从稀疏数组的第二行开始读取 chessArray2[sparseArray[i][0]][sparseArray[i][1]]=sparseArray[i][2]; //认真理解 } System.out.println(); //输出恢复后的二维数组查看 System.out.println(); System.out.println("恢复后的二维数组如下:"); for (int[] row:chessArray2){
for (int data:row){
System.out.printf("%d\t",data); //格式化输出 } System.out.println(); //换行 }
4,IO流实现稀疏数组的读写磁盘操作
实现以下操作:
- 需求一:在以上基础上,将稀疏数组保存在磁盘上,如:保存为map.data
- 需求二:恢复原来的数组时,读取map.data进行恢复
需求一解决方案:
//使用IO流将稀疏数组保存磁盘文件map.data进行存档 File destFile = new File("map.data"); BufferedWriter bw = null; try {
bw=new BufferedWriter(new FileWriter(destFile)); for (int[] row:sparseArray){
for (int data:row){
bw.write(data+"\t"); } bw.write("\n"); //换行 } } catch (IOException e) {
e.printStackTrace(); } finally {
if (bw!=null){
try {
bw.close(); } catch (IOException e) {
e.printStackTrace(); } } }
//从硬盘文件中读取数据,并转换为稀疏数组。为了便于读取,使用一个list对稀疏数组中的元素进行存储 BufferedReader br= null; File srcFile = new File("map.data"); List<Integer> list = new ArrayList<>(); try {
br=new BufferedReader(new FileReader(srcFile)); String line; while ((line=br.readLine())!=null){
//读取每一行的数据 String[] str = line.split("\t"); //返回一个个元素构成的数组 for (int i=0;i<str.length;i++){
list.add(Integer.parseInt(str[i])); //把每个数组元素都添加到list集合中去,便于读取 } } } catch (IOException e) {
e.printStackTrace(); } finally {
if (br!=null){
try {
br.close(); } catch (IOException e) {
e.printStackTrace(); } } } //读取list集合数据,得到稀疏数组的行数。(有了行数就可以创建稀疏数组) //其中list.get(2)取到的是数组中第三个元素,即稀疏数组第一行第三列元素,代表了非零元素个数。非零元素个数加一即为稀疏数组行数 int row=list.get(2)+1; //list中get方法的参数为索引 System.out.println("稀疏数组的行数为:"+row); //3 //创建稀疏数组 int sparseArray2[][] = new int[row][3]; //sparseArray2[0][0]=list.get(0); //sparseArray2[0][1]=list.get(1); //sparseArray2[0][2]=list.get(2); //sparseArray2[1][0]=list.get(3); //sparseArray2[1][1]=list.get(4); //sparseArray2[1][2]=list.get(5); //找到循环赋值规律 //进行循环赋值(此处是读取文件内容恢复到稀疏数组核心) int j=0; //通过j控制行 for (int i=0;i<list.size();i=i+3){
//稀疏数组每行三个元素,赋值完一行,循环一次 sparseArray2[j][0]=list.get(i); sparseArray2[j][1]=list.get(i+1); sparseArray2[j][2]=list.get(i+2); j++; //每一行的三个数赋值结束,当前行数随之增加一 } //输出解析出来的稀疏数组样式查看 System.out.println(); System.out.println("解析文件后得到的稀疏数组为如下形式:"); for(int i=0;i<sparseArray2.length;i++){
System.out.printf("%d\t%d\t%d\t\n",sparseArray2[i][0],sparseArray2[i][1],sparseArray2[i][2]); }
代码执行结果:

至此成功解析硬盘文件,恢复成稀疏数组!此即为“续上盘”功能。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/217755.html原文链接:https://javaforall.net
