稀疏数组
-
当一个数组中大部分元素为0或者为同一个值时,可以使用稀疏数组来保存该数组。
-
把一个大部分元素为0的数组转化为稀疏数组的方法:
- 记录数组一共有几行几列,有多少个不同的值
- 把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
-
稀疏数组的本质就是元素为三元组的数组。
-
稀疏数组应用:
-
在科学与工程领域中求解线性模型时经常出现大型的稀疏矩阵。在使用计算机存储和操作稀疏矩阵时,经常需要修改标准算法以利用矩阵的稀疏结构。由于其自身的稀疏特性,通过压缩可以大大节省稀疏矩阵的内存代价。更为重要的是,由于过大的尺寸,标准的算法经常无法操作这些稀疏矩阵。
-
从描述我们可以知道,稀疏数组主要应用有压缩数据和优化数据结构。
- 原数组转为稀疏数组的思路:
因为我们需要知道要用多大的空间去存储原数组中的非0元素,并且在逆过程中重构原数组,所以我们应该知道原数组的行列,每个非0数组元素的行列位置以及值。
- 遍历原数组得到非0元素的个数n。
- 构造n + 1 (第一行储存原数组的行列和非0元素的个数)行,3 列的数组。
- 遍历将非0元素存入稀疏数组。
*代码实现:
public class SparseArrayDemo {
/**
* return a sparse array,but the array just have the first nonempty line which contains
* the row and column number of original array and a number of nonempty elements.
* @param originalArray
* @return
*/
static int [][] returnSEmptySparseArray(int [][] originalArray){
//traverse the original array to get the number of nonempty value.
int numberOfNonemptyValue = 0;
for (int i = 0;i < originalArray.length;i ++){
for(int j = 0;j < originalArray[0].length;j ++){
if(originalArray[i][j] != 0){
++ numberOfNonemptyValue;
}
}
}
int [][] emptySparseArray = new int[numberOfNonemptyValue + 1][3];
emptySparseArray[0][0] = originalArray.length;
emptySparseArray[0][1] = originalArray[0].length;
emptySparseArray[0][2] = numberOfNonemptyValue;
return emptySparseArray;
}
/**
* return the sparse array
* @param originalArray
* @return
*/
public static int [][] returnSparseArray(int [][] originalArray){
int [][] emptySparseArray = returnSEmptySparseArray(originalArray);
int count = 1;
for(int i = 0;i < originalArray.length;i ++){
for (int j = 0;j < originalArray[0].length;j ++){
if(originalArray[i][j] != 0){
//read nonempty element into empty sparse array from original array.
emptySparseArray[count][0] = i;
emptySparseArray[count][1] = j;
emptySparseArray[count][2] = originalArray[i][j];
++ count;
}
}
}
return emptySparseArray;
}
/**
* convert the sparse array back to original array
* @param sparseArray
* @return
*/
public static int [][] returnOriginalArray(int [][] sparseArray){
if(sparseArray == null){
return null;
}
int [][] originalArray = new int[sparseArray[0][0]][sparseArray[0][1]];
for(int i = 1;i <= sparseArray[0][2];i ++){
originalArray[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
}
return originalArray;
}
}
- 测试代码:
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class SparseArrayTest {
private int [][] array = new int[10][10];
@BeforeEach
public void setUp(){
array[1][1] = 1;
array[7][8] = 1;
array[2][1] = 1;
array[9][9] = 1;
array[7][7] = 1;
array[2][9] = 1;
}
@Test
public void testReturnSEmptySparseArray(){
int [][] sparseArray = SparseArrayDemo.returnSEmptySparseArray(array);
for(int i = 0; i < sparseArray.length;i ++){
for(int j = 0;j < 3;j ++){
System.out.print(sparseArray[i][j] + " ");
}
System.out.println();
}
}
@Test
public void testReturnSparseArray(){
int [][] sparseArray = SparseArrayDemo.returnSparseArray(array);
for(int i = 0; i < sparseArray.length;i ++){
for(int j = 0;j < 3;j ++){
System.out.print(sparseArray[i][j] + " ");
}
System.out.println();
}
}
@Test
public void testReturnOriginalArray(){
int [][] sparseArray = SparseArrayDemo.returnSparseArray(array);
int [][] originalArray = SparseArrayDemo.returnOriginalArray(sparseArray);
for(int i = 0;i < originalArray.length;i ++){
for(int j = 0;j < originalArray[0].length;j ++){
System.out.print(originalArray[i][j] + " ");
}
System.out.println();
}
}
}
- 输出:
10 10 6
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
10 10 6
1 1 1
2 1 1
2 9 1
7 7 1
7 8 1
9 9 1
0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1
注意,稀疏数组元素的行列值是数组下标。
- 这里我们添加一个测试把稀疏数组存入文件中,再读出来转换为原数组:
@Test
public void testSaveSparseArrayInFileAndReverse() throws IOException, ClassNotFoundException {
int [][] sparseArray = SparseArrayDemo.returnSparseArray(array);
File file = new File("./test.txt");
if(!file.exists()){
file.createNewFile();
}
//write the sparse array into a file.
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
objectOutputStream.writeObject(sparseArray);
//read the sparse array from the file
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
sparseArray = (int[][]) objectInputStream.readObject();
int [][] originalArray = SparseArrayDemo.returnOriginalArray(sparseArray);
for(int i = 0;i < originalArray.length;i ++){
for(int j = 0;j < originalArray[0].length;j ++){
System.out.print(originalArray[i][j] + " ");
}
System.out.println();
}