为什么说从一开始学呢,这类的博客,是之前有C或C++数据结构基础和Java基础,重新刷一遍Java数据结构时留下的,作为学习笔记放上来,在文章最后放上某站的学习视频连接,可以去看,视频讲的还是非常好的,下面开始进入正题。
概念
当一个数组中大部分元素为0,或者为同一个值的时候,用一种方法,将零或大量的相同数据丢弃,只记录剩余的必要数据,以达到压缩数据量的效果,并且在需要的时候可以还原回原来的数组,这种情况就可以使用稀疏数组来保存改数组。
处理方法
1.记录原二维数组一共有几行几列,有多少个不同的值。
2.把具有不同值得元素和行列及值记录在一个小规模得数组(稀疏数组)中,从而缩小程序得规模
举例说明
如下左图的一个二维数组,该数组中有大量的0值。
1.在稀疏数组中第一行存放原先二维数组的行列和不为0的值
2.将不为零的位置和值依次放入稀疏数组中
3.得到如下右图的一个新的93的二位数字(稀疏数组)
这样原先本来是67=42个数据的二维数组,现在被压缩之后就成了9*3=27的新的一个二维数组,也就是我们需要的稀疏数组
代码思路分析:
二维数组→稀疏数组
1.先遍历原二维数组,得到有效数据sum个
2.根据sum可以创建稀疏数组spareArray int[sum+1][3]
3.将二维数组的有效数据存入稀疏数组中
稀疏数组→二维数组
1.先读取稀疏数组的第一行,根据第一行的值,创建二维数组chessArr2 = int[][]
2.再读取稀疏数组的后面几行的值,并按位置赋给原来的二位数组
案例引入
假设有一个需求:要求编写一个五子棋程序,要求能有存盘退出和继续上盘的功能。
问题分析:
用一个二维数组去代表棋盘,在二维数组里面用不同的值,表示空、黑棋、蓝棋三种状态,在退出的时候,将该二维数组写入文件,在继续上盘的时候,将该文件读取出来。
存在的问题:
该棋盘能转换为一个11乘11的二维数组,如果棋盘上的棋较少的时候,大部分都为空时,将该11*11的二维数组全部写入文件,就是一种很大的资源浪费,这个时候就需要将该数组压缩——→采用稀疏数组
代码实现
针对上面的棋盘需求,我们就写一个代码,用稀疏数组取实现
package com.sparsearray;
/**
* 稀疏数组
* @author centuowang
* @param
* chessArr1:原始二维数组
* sparseArr:稀疏数组
* chessArr2:原由稀疏数组转换回来的二维数组
* sum:遍历原始二维数组中得到的不为零的数据个数
* count:计数器,用于确定数据应该放在稀疏数组的第几行
*/
public class SparseArray {
public static void main(String[] args) {
//先创建一个二维数组表示原本的棋盘和棋子状态
//棋盘为11*11的二维数组
int chessArr1[][] = new int[11][11];
//1表示黑子,2表示篮子,其他没赋值的数组会自动赋0表示空
chessArr1[1][2] = 1;
chessArr1[2][3] = 2;
//打印输出以下这个二维数组
System.out.println("原始的二维数组");
for(int[] row: chessArr1) {//第一次遍历取行
for(int data: row) {//第二次遍历取行中的数据
System.out.printf("%d\t",data);
}
//每打完一行记得换行
System.out.println();
}
//开始进行稀疏数组的转化
//因为通常情况下我们对二维数组内的数据情况并不知道,所以先遍历一下原始的二维数组,得到有多少个非零数据
int sum = 0;//用一个int变量存放一下不为零的数据个数
for(int[] row: chessArr1) {
for(int data: row) {
if(data != 0) {
sum++;
}
}
}
System.out.println("原二维数组中不为零的数据个数为:"+sum+"个");
//开始创建稀疏数组
int sparseArr[][] = new int[sum+1][3];
//先将原始二维数组的行数和列数存入稀疏数组中
sparseArr[0][0] = 11;
sparseArr[0][1] = 11;
sparseArr[0][2] = sum;
//开始将原二维数组中不为零的数据按位置存入稀疏数组中
int count = 0;//计数器
for(int i=0 ; i<chessArr1.length; i++) {
for(int j=0; j<chessArr1[i].length; j++) {
if(chessArr1[i][j] != 0) {
count++;//放入稀疏数组的第几行呢?,这里就需要一个计数器,用一个整型变量count表示
sparseArr[count][0] = i;//往稀疏数组的第一列存入不为零数据所在原二维数组的行数
sparseArr[count][1] = j;//往稀疏数组的第二列存入不为零数据所在原二维数组的列数
sparseArr[count][2] = chessArr1[i][j];//往稀疏数组的第三列存入不为零的数据
}
}
}
//打印检测一下该稀疏数组
System.out.println("转化得到的稀疏数组");
for(int[] row: sparseArr) {
for(int data: row) {
System.out.printf("%d\t",data);
}
//每打完一行记得换行
System.out.println();
}
//将稀疏数组转换回原来的二维数组
//先读取稀疏数组的第一行,确定原二维数组的大小
int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]];
for(int i=1 ; i<sparseArr.length; i++) {
for(int j=0 ; j<sparseArr[i].length; j++) {
chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][j];
}
}
//打印检测一下由稀疏数组转换回来的二维数组
System.out.println("由稀疏数组转换回来的二维数组");
for(int[] row: chessArr2) {
for(int data: row) {
System.out.printf("%d\t",data);
}
//每打完一行记得换行
System.out.println();
}
}
}
最终运行的结果,在控制台我们可以看到打印输出的二维数组与稀疏数组之间的转化如下图
下一篇:从1开始学Java数据结构与算法——用数组实现队列与环形队列