1.什么是稀疏数组?
百度百科的定义如下:https://baike.baidu.com/item/%E7%A8%80%E7%96%8F%E7%9F%A9%E9%98%B5/3249303?fr=aladdin
稀疏数组也是二维数组,是一种较为特殊的二维数组。存储的元素是在一个非常大的二维数组中找出有效元素进行存储,但存储的元素一般较少且没有规律,所以称为稀疏数组。
2.为什么会有稀疏数组(及其应用)?
设想一个场景,在一款APP上与电脑进行五子棋博弈,而又突然有事但棋局又不想毁掉,这个时候可以选择存档保存,而针对这种棋局的存档保存一般用二维数组进行保存。再把场景拉伸一步,假设博弈时下的棋子一共就不超过10子(tip:五子棋现在国际通用格式为15x15的规格)。如图:
如果采用常规的二维数组进行存储,那么需要一个15x15的二维数组,能存放的元素个数是15x15个,而真正有意义的元素却只有不超过10个,而剩下的存储空间就多余以至于浪费了。
这个时候就产生了稀疏数组,只存储有效数据,而棋局的规格大小(什么时候用稀疏数组还是得根据上面稀疏数组的定义进行定夺)
上面的五子棋局对应的稀疏数组为(在程序中都是以0开始数数的):
解释一下这个稀疏数组,首先第一行存的是棋局的规格和棋局中有效的元素个数,因为黑白子个一个所以有效元素为2个,棋局是一个15x15规格的大小。而后稀疏数组的其他行就存储有效元素的位置以及值(ps:这里假定黑棋值为1,白棋值为2)。这样就把二维数组转为稀疏数组进行存储了,而且省了很多空间
如何用java代码进行二维数组与稀疏数组的转换呢?
以此图作为转换,先做以下定义,把五子棋棋谱上空的元素值定义为0,黑棋值定义为1,白棋值定义为2。
稀疏数组的列是固定的三列,行数是二维数组有效元素个数+1,因为稀疏数组第一行存的数据是二维数组的规格以及二维数组有效元素个数。所以创建稀疏数组时需要先知道二维数组的规格和有效元素。
二维数组转稀疏数组的思路:
1)遍历二维数组获取二维数组twoArr中有效元素的个数,设为count,然后创建一个二维数组用来表示稀疏数组
int[][] sparseArr = new int[count+1][3]
2)给稀疏数组的第一行赋值:
sparseArr[0][0] = twoArr.length
sparseArr[0][1] = twoArr[0].length
sparseArr[0][2] = count
3)遍历二维数组,当遍历的元素不为0时,给稀疏数组添加一行,直至遍历完整个二维数组
稀疏数组转二维数组思路:
1) 读取稀疏数组第一行,可以得知二维数组的规格从而创建一个二维数组
int row = sparseArr[0][1]
int col = sparseArr[0][2]
int[][] twoArr = new int[row][col]
2)遍历稀疏数组,把有效元素还原到二维数组
i 表示遍历的稀疏数组行数
sparseArr[i][0]表示二维数组数据的行
sparseArr[i][1]表示二维数组数据的列
sparseArr[i][2]表示二维数组数据的值
还原到二维数组:
twoArr[array[i][0]][array[i][1]] = array[i][2]
先定义一个15x15的二维数组,并把对应的黑白棋元素填上,为了二维数组更好的输出,对其进行格式化的输出,代码如下:
public static void printArray(int[][] array){
for (int i = 0; i <array.length ; i++) {
for (int j = 0; j <array[i].length ; j++) {
System.out.printf("%3d",array[i][j]);
}
System.out.println("");
}
}
传入一个二维数组,对其进行打印:
public static void main(String[] args) {
int [][] arr = new int[15][15];
arr[2][2] = 1;
arr[3][3] = 2;
System.out.println("-----原二维数组-----");
printArray(arr);
}
创建一个方法,传入一个二维数组,最后返回一个稀疏数组:
public static int[][] twoArrToSparseArr(int[][] array){//二维转稀疏
int count = 0;//先遍历二维数组,计算出稀疏数组的行数,稀疏数组行数=二维数组中非0数的个数+1
for (int i = 0; i <array.length ; i++) {
for (int j = 0; j <array[i].length ; j++) {
if (array[i][j]!=0){
count = count + 1;
}
}
}
//创建一个稀疏数组
int[][] sparseArr = new int[count+1][3];
//创建一个稀疏数组行标,用于指示当前是稀疏数组第几行,初始化时指向第一行
int p = 0;
//稀疏数组的第一行初始化
sparseArr[p][0] = array.length;//二维数组的行数
sparseArr[p][1] = array[0].length;//二维数组的列数
sparseArr[p][2] = count;//二维数组中非0数的个数
//遍历二维数组转换成稀疏数组
for (int i = 0; i <array.length ; i++) {
for (int j = 0; j <array[i].length ; j++) {
if (array[i][j]!=0){
//当二维数组的某个元素不为0,将稀疏数组行标向下移一位
p = p + 1;
//依次给稀疏数组的列赋值
sparseArr[p][0] = i;
sparseArr[p][1] = j;
sparseArr[p][2] = array[i][j];
}
}
}
return sparseArr;
}
最后测试:
public static void main(String[] args) {
int [][] arr = new int[15][15];
arr[2][2] = 1;
arr[3][3] = 2;
System.out.println("-----原二维数组-----");
printArray(arr);
int[][] sparseArr = twoArrToSparseArr(arr);
System.out.println("-----稀疏数组-----");
printArray(sparseArr);
}
二维数组能转为稀疏数组,自然需要稀疏数组转为二维数组:
创建一个方法,传入一个稀疏数组,最后返回一个二维数组:
public static int[][] sparseArrToTwoArr(int[][] array){
//从稀疏数组的第一行读取二维数组的行和列
int row = array[0][0];
int col = array[0][1];
int[][] twoArr = new int[row][col];
for (int i = 1; i < array.length; i++) {//二维数组中的非0数的数据从稀疏数组的第二行开始读取
//array[i][0]表示二维数组数据的行
//array[i][1]表示二维数组数据的列
//array[i][2]表示二维数组数据的值
twoArr[array[i][0]][array[i][1]] = array[i][2];
}
return twoArr;
}
测试:
public static void main(String[] args) {
int [][] arr = new int[15][15];
arr[2][2] = 1;
arr[3][3] = 2;
System.out.println("-----原二维数组-----");
printArray(arr);
int[][] sparseArr = twoArrToSparseArr(arr);
System.out.println("-----稀疏数组-----");
printArray(sparseArr);
int[][] twoArr = sparseArrToTwoArr(sparseArr);
System.out.println("-----再转回二维数组-----");
printArray(twoArr);
}
至此稀疏数组与二维数组的转换代码就完成了,至于什么时候转换为稀疏数组以及最后保存文件等等方式,就可以根据具体需求具体分析了。