稀疏数组能将一个二维数组进行压缩,节省存储空间。稀疏数组的列数固定为 3,对于原始数组中的某个有效元素,会对应稀疏数组中的一行,依次记录其在原始数组中的行、列、值
三个信息。其本质还是一个二维数组,因此也是非线性结构。
相关源码:https://gitee.com/flying-morning/data-structure/tree/master/src/com/datastructure/sparse
1 应用场景
当一个数组中大部分元素为0或者同一个值,可以使用稀疏数组,核心就两点:
- 记录一个数组的
行、列数,不同的值个数
; - 把具有不同值的
元素的行、列以及值的信息
记录在一个小规模数组中
下面这个图就是网上流传比较广的一个普通数组转稀疏数组的图,这里借用下。
2 稀疏数组和普通数组的转换
普通二维数组转为稀疏数组:
- 遍历原始数据,得到不同元素(有效元素)的个数 count;
- 创建稀疏数组, sparsearray[count+1][3],行数是有效元素个数加1;
- 将普通数组中的有效数据记录到稀疏数组。稀疏数组,第一行分别记录原始数组的
总行数、总列数、有效值个数
;后面每一行则记录一个数据元素,依次对应在原始数组中的行号、列号、值
。
//将二维原始数组转换为稀疏数组
public int[][] convertToSparseArr (int[][] originArray) {
int rowLen= originArray.length;
int colLen = originArray[0].length;
//有效元素个数
int numOfValidElement = countValidElement(originArray);
int[][] sparerArray = new int[numOfValidElement+1][3];
//稀疏数组的第一行
sparerArray[0][0] = rowLen;
sparerArray[0][1] = colLen;
sparerArray[0][2] = numOfValidElement;
//生成稀疏数组的元素
int count = 0; //第几(count)个有效元素
for (int i=0;i<rowLen;++i) {
for (int j=0;j<colLen;++j) {
if (originArray[i][j] !=0) {
++count;
sparerArray[count][0] = i;
sparerArray[count][1] = j;
sparerArray[count][2] = originArray[i][j];
}
}
}
return sparerArray;
}
稀疏数组转为原始数组:
- 读取稀疏数组第一行,获取原始数组的行数、列数,并创建原始数组;
- 读取稀疏数据后续每一行数据,根据行、列、值信息,填充原始数组。
//将稀疏数组转换为原始二维数组
public int[][] convertToOriginArr(int[][] sparseArray) {
//获取原始数组行列信息
int rowLen = sparseArray[0][0];
int colLen = sparseArray[0][1];
int[][] originArray = new int[rowLen][colLen];
for(int i=1;i<sparseArray.length;++i) {
int[] line = sparseArray[i];
originArray[line[0]][line[1]] = line[2];
}
return originArray;
}
3 结果验证以及完整源码
3.1 结果验证
生成的原始数组,3 个有效元素:
转换成稀疏数组:
再通过稀疏数组转换成原始数组:
3.2 完整源码
更多数据结构相关源码,欢迎访问码云获取,https://gitee.com/flying-morning/data-structure/tree/master/src/com/datastructure/sparse
import java.util.Random;
public class SparseArray {
public static void main(String[] args) {
SparseArray mSparseArr = new SparseArray();
//创建原始二维数组
int[][] originArr = mSparseArr.generateOriginArr();
mSparseArr.printArr(originArr,"原始数组");
//生成稀疏数组
int[][] sparseArr = mSparseArr.convertToSparseArr(originArr);
mSparseArr.printArr(sparseArr,"稀疏数组");
//将稀疏数组转换成普通二维数组
int [][] originArrFromSparse = mSparseArr.convertToOriginArr(sparseArr);
mSparseArr.printArr(originArrFromSparse,"从稀疏数组还原后的数组");
}
/**
* 生成原始二维数组 10*10
* 随机选择三个位置,产生非 0 有效数字
*/
public int[][] generateOriginArr() {
int[][] originArr = new int[10][10];
//to generate 3 non-zero number
Random random = new Random();
for(int i=0;i<3;++i) {
int row = random.nextInt(9);
int col = random.nextInt(9);
originArr[row][col] = 1;
}
return originArr;
}
//打印数组
public void printArr(int[][] array,String type) {
System.out.println(type + ":");
for(int[] row:array) {
for(int num:row) {
System.out.print(num + "\t");
}
System.out.println();
}
}
//将二维原始数组转换为稀疏数组
public int[][] convertToSparseArr (int[][] originArray) {
int rowLen= originArray.length;
int colLen = originArray[0].length;
//有效元素个数
int numOfValidElement = countValidElement(originArray);
int[][] sparerArray = new int[numOfValidElement+1][3];
//稀疏数组的第一行
sparerArray[0][0] = rowLen;
sparerArray[0][1] = colLen;
sparerArray[0][2] = numOfValidElement;
//生成稀疏数组的元素
int count = 0; //第几(count)个有效元素
for (int i=0;i<rowLen;++i) {
for (int j=0;j<colLen;++j) {
if (originArray[i][j] !=0) {
++count;
sparerArray[count][0] = i;
sparerArray[count][1] = j;
sparerArray[count][2] = originArray[i][j];
}
}
}
return sparerArray;
}
//统计原始数组中有效元素(非0)的个数,尽管我们知道是 3
private int countValidElement(int[][] originArray) {
int count = 0;
for(int[] row:originArray) {
for (int num : row) {
if (num != 0) {
++count;
};
}
}
System.out.println("有效元素个数为: " + count);
return count;
}
//将稀疏数组转换为原始二维数组
public int[][] convertToOriginArr(int[][] sparseArray) {
//获取原始数组行列信息
int rowLen = sparseArray[0][0];
int colLen = sparseArray[0][1];
int[][] originArray = new int[rowLen][colLen];
for(int i=1;i<sparseArray.length;++i) {
int[] line = sparseArray[i];
originArray[line[0]][line[1]] = line[2];
}
return originArray;
}
}