一 、什么是稀疏数组
稀疏数组可以看做是普通数组的压缩,但是这里说的普通数组是值无效数据量远大于有效数据量的数组。例如:0是无效的数据,只有1、2、4、6是有效的。
0 0 0 0 1 0 0
0 0 2 0 0 0 0
0 0 0 0 0 0 4
0 0 0 0 6 0 0
二、普通数组转为稀疏数组
稀疏数组列数是固定的,为三列,行数不固定。第一行的row是普通数组的行数,col是普通数组的列数,value是有效数据的个数,剩下的行数是有效数据的坐标及数据值。
例如下面的普通数组,
row col value
0 0 0 0 1 0 0 4 7 4 一共有4行7列,1、2、4、6四个有效数据。
0 0 2 0 0 0 0 4 0 1 1是有效数据,它在普通数组坐标是(4,0)
0 0 0 0 0 0 4 1 2 2 2是有效数据,它在普通数组坐标是(1,2)
0 0 0 0 6 0 0 2 6 4 4是有效数据,它在普通数组坐标是(2,6)
3 4 6 6是有效数据,它在普通数组坐标是(3,4)
实际上稀疏数组比普通数组多一行
三、代码
1、稀疏数组
import java.util.*;
/**
* 稀疏数组
* 第一行存储原始数据总行数,总列数,总的非0数据个数(行数=有效数据+1,列数是3,固定的)
* 接下来每一行都存储非0数所在行,所在列,和具体值
* 0 0 0 0 row col val
* 0 1 0 0 4 4 3
* 0 0 2 0 1 1 1
* 0 0 3 0 2 2 2
* 3 2 3
*/
public class SparseArray {
/**
* 转为稀疏数组的算法:
* 1、遍历数组,得到有效元素的个数effectiveNum。
* 2、创建稀疏数组,行数为effectiveNum+1。 int[effectiveNum+1][3]
* 3、将有效数据存入稀疏数组即可。
*/
public int[][] toSpaeseArray(int[][] arr, int invalidData) {
final List<List<Integer>> effectiveList = getEffectiveList(arr, invalidData);
//有效元素的个数
final int effectiveNum = effectiveList.size();
//创建稀疏数组
final int[][] spaeseArray = new int[effectiveNum + 1][3];
//赋值
spaeseArray[0][0] = arr.length;
spaeseArray[0][1] = arr[0].length;
spaeseArray[0][2] = effectiveNum;
for (int i = 1; i <= effectiveNum; i++) {
spaeseArray[i][0] = effectiveList.get(i - 1).get(0);
spaeseArray[i][1] = effectiveList.get(i - 1).get(1);
spaeseArray[i][2] = effectiveList.get(i - 1).get(2);
}
return spaeseArray;
}
/**
* 获取有效的数据
*
* @param arr
* @param invalidData 无效的数据
* @return 返回的list 下标分别对应的是 0:行 1:列 2:有效的数据
*/
public List<List<Integer>> getEffectiveList(int[][] arr, int invalidData) {
final List<List<Integer>> result = new ArrayList<>();
if (arr.length == 0) {
throw new RuntimeException("数组不能为空!");
}
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (arr[i][j] != invalidData) {
final List<Integer> list = new ArrayList();
//行
list.add(i);
//列
list.add(j);
//值
list.add(arr[i][j]);
result.add(list);
}
}
}
return result;
}
/**
* 稀疏数组转为原始数组
* 1、获取第一行的数据,建立原始数组 arr= int[arr[0][0]][arr[0][1]]
* 2、读取稀疏数组后几行数组,并赋给原始数组
*
* @param arr
* @return
*/
public int[][] spaeseArray2Array(int[][] arr, int invalidData) {
final int[][] result = new int[arr[0][0]][arr[0][1]];
Set<Integer> set = new HashSet<>();
for (int i = 1; i < arr.length; i++) {
result[arr[i][0]][arr[i][1]] = arr[i][2];
set.add(arr[i][2]);
}
if (invalidData != 0) {
for (int i = 0; i < result.length; i++) {
for (int j = 0; j < result[i].length; j++) {
if (!set.contains(result[i][j])) {
result[i][j] = invalidData;
}
}
}
}
return result;
}
}
2、数组工具类(创建二维数组)
import java.util.Arrays;
import java.util.Random;
/**
* 线性结构:数组、队列、链表、栈
* 非线性结构:多维数据、树结构、图结构
*/
public class Array {
/**
* 随机生成二维数组
* @param row 行
* @param col 列
* @param invalidData 无效的填充数据
* @return
*/
public static int[][] genert2DArray(int row, int col, int invalidData) {
final int[][] arr = new int[row][col];
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
double random = Math.random();
Random random1 = new Random();
if (random > 0.8) {
arr[i][j] = random1.nextInt(100);
} else {
arr[i][j] = invalidData;
}
}
}
return arr;
}
/**
* 二维数组 toString
*/
public static void toString(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(Arrays.toString(arr[i]));
}
}
}
四、测试
public static void main(String[] args) {
final SparseArray sparseArray = new SparseArray();
//随机生成二维数组
int[][] arr = Array.genert2DArray(5, 5, 0);
Array.toString(arr);
System.out.println("------------------------");
//转为稀疏数组
int[][] arr1 = sparseArray.toSpaeseArray(arr, 0);
Array.toString(arr1);
System.out.println("------------------------");
//稀疏数组还原为普通数组
int[][] arr2 = sparseArray.spaeseArray2Array(arr1, 0);
Array.toString(arr2);
}
结果:
[35, 85, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 77, 0, 0, 0]
[0, 0, 0, 0, 0]
[90, 3, 0, 0, 0]
------------------------
[5, 5, 5]
[0, 0, 35]
[0, 1, 85]
[2, 1, 77]
[4, 0, 90]
[4, 1, 3]
------------------------
[35, 85, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 77, 0, 0, 0]
[0, 0, 0, 0, 0]
[90, 3, 0, 0, 0]