稀疏数组
简介:当编写的二维数组中存在很多不用的点但初始化时都赋值为0时,这个二维数组的观赏性很低并且非常浪费存储空间,这个时候会选择使用稀疏数组对这个二维数组进行简化压缩。
稀疏数组
是当一个二维数组大部分数据为0
或其他相同数据
时,对这个数组的一种简化的保存形式。
处理规则:
①记录二维数组有几行几列,并把不同值的元素
保存下来。
②记录不同值元素的坐标,并把它保存在一个小数组中,从而缩小程序规模。
用一个简单模型进行直观分析:
下图是一个11×11
的二维数组
,其中有两个非0元素(上述①的不同值的元素
)
转化为稀疏数组:
- 第一行记录数组的总行列数以及有值元素的个数;
- 之后的每行都会记录各个非零元素的“坐标”以及数值);
- 稀疏数组固定为“行”、“列”、“值”3列,行数由
不同值的元素
个数决定。
二维数组——>稀疏数组
- 遍历二维数组,记录
不同值的元素
的个数sum; - 根据有效数据的个数创建新的数组,作为稀疏数组
//行数为“不同值的元素个数+1”:
//因为第一行是记录“二维数组的行列数”和“不同值的元素个数”
int[ ][ ] sparseArr=new int [sum+1][3];
//列数固定为3
-
将原始二维数组中的有效数据存入新建数组中。
在实际应用当中,填充完毕的稀疏数组需要存盘到一个文件中,也就是把计算机中的信息存储到磁盘上,多用于游戏存档读档(比如说围棋游戏就很适合),并且可以恢复成原始的二维数组
操作流程:
- 第一步:创建并输出原始二维数组
public class SparseArray {
public static void main(String[] args) {
//创建一个大小为11*11的二维数组
int chessArr1[][] = new int[11][11];
//定义两个不同值数据
chessArr1[2][2] = 3;
chessArr1[6][4] = 8;
//遍历输出二维数组
//遍历棋盘二维数组中的每一行
for (int row[] : chessArr1) {
//遍历每一行的每一个元素
for (int data : row) {
System.out.printf("%d\t", data);
}
//每输出一行就换行
System.out.println();
}
}
}
运行结果图:
- 第二步:计算有效数据的个数
//将二维数组转换压缩成稀疏数组的思路
//1.首先遍历二维数组并计算有效数据的个数
int sum = 0;//计算有效数据的个数
for (int row[] : chessArr1) {
//遍历每一行的每一个元素
for (int data : row) {
if (data != 0)
sum++;
}
}
System.out.println(sum);
运行结果图:
- 第三步:填充稀疏数组并将其打印出来
int[][] sparseArr = new int[12][3];//行数为sum+1,列数固定为3
//初始化稀疏数组第一行
sparseArr[0][0] = 11;
sparseArr[0][1] = 11;
sparseArr[0][2] = sum;
// 遍历二维数组,将非零的值存入sparseArr(稀疏数组)中
int count = 0;// count用于记录是第几个有效元素
for (int i = 0; i < 11; i++) {// 遍历每一行
for (int j = 0; j < 11; j++) {// 遍历每一列
if (chessArr1[i][j] != 0) {// 如果发现有效数据
// sparseArr[?][0]=i;//第一列的值就是该有效元素的行数
// sparseArr[?][1]=j;//第二列的值就是该有效元素的列数
// sparseArr[?][2]=chessArr1[i][j];//第三列的值就是该有效元素其本身
count++;
sparseArr[count][0] = i;
sparseArr[count][1] = j;
sparseArr[count][2] = chessArr1[i][j];
}
}
}
System.out.println();
System.out.println("压缩成稀疏数组表现为:");
// 遍历打印稀疏数组
for (int i = 0; i < sum + 1; i++) {
//格式化输出每一行的三列数,并且每打印三个数换行
System.out.printf("%d\t %d\t %d\t", sparseArr[i][0], sparseArr[i][1], sparseArr[i][2]);
System.out.println();
}
运行结果图:
稀疏数组——>二维数组
- 先读取稀疏数组第一行,得到二维数组的行列数,创建一个新的二维数组(请看上面的二维数组⬆)
int [ ][ ]=new int [11][11];
-
再读取剩下几行的数据即可
在实际应用当中,先将文件恢复成稀疏数组,再转换成原始二维数组
操作流程:
-
第一步:读取稀疏数组的值恢复原始的二维数组
-
第二步:读取稀疏数组后几行数据,将有效值填充到二维数组的指定位置
// 将稀疏数组转换为二维数组的思路
// 1.读取稀疏数组第一行的值,根据第一行的值来创建原始的二维数组
int[][] chessArr2 = new int[sparseArr[0][0]][sparseArr[0][1]];
// 2.读取后几行的数据填充二维数组
for (int i = 1; i < sparseArr.length; i++) {// 因为是从第二行开始读数的,所以要从i=1开始
chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
}
// 输出原始的二维数组
System.out.println();
System.out.println("打印恢复后的二维数组");
for (int[] row : chessArr2) {
for (int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
运行结果图:
在上面的基础上,将稀疏数组保存到磁盘“map.data”上,恢复原来的数组时,读取“map.data”进行恢复。
完整code
import java.awt.Desktop;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class SparseArray {
public static void main(String[] args) throws Exception {// 在方法声明部分使用,表示该方法可能产生此异常,如果在方法声明处使用了throws
// 声明异常,则该方法产生异常也不必捕获,会直接把异常抛出到调用该方法的地方。
// 创建一个原始的二维数组11*11
int chessArr1[][] = new int[11][11];
chessArr1[2][2] = 3;
chessArr1[6][4] = 8;
// 输出原始的二维数组
System.out.println("原始二维数组:");
for (int[] row : chessArr1) { // 遍历棋盘二维数组中的每一个一维数组
for (int data : row) { // 遍历一维数组中的每一个元素
System.out.printf("%d\t", data);
}
System.out.println();
}
// 将二维数组转换为稀疏数组的思路
// 1.首先遍历二维数组并计算有效数据的个数
int sum = 0;// 计算有效数据的个数
for (int i = 0; i < chessArr1.length; i++) {
for (int j = 0; j < chessArr1.length; j++) {
if (chessArr1[i][j] != 0) {
sum++;
}
}
}
// 2.创建对应的稀疏数组 (int[ ][ ] sparseArr=new int [sum+1][3];)
int[][] sparseArr = new int[sum + 1][3];
sparseArr[0][0] = 11;
sparseArr[0][1] = 11;
sparseArr[0][2] = sum;
// 遍历二维数组,将非零的值存入sparseArr(稀疏数组)中
int count = 0;// count用于记录是第几个有效元素
for (int i = 0; i < chessArr1.length; i++) {// 遍历每一行
for (int j = 0; j < chessArr1.length; j++) {// 遍历每一列
if (chessArr1[i][j] != 0) {// 如果发现有效数据
// sparseArr[?][0]=i;//第一列的值就是该有效元素的行数
// sparseArr[?][1]=j;//第二列的值就是该有效元素的列数
// sparseArr[?][2]=chessArr1[i][j];//第三列的值就是该有效元素其本身
count++;
sparseArr[count][0] = i;
sparseArr[count][1] = j;
sparseArr[count][2] = chessArr1[i][j];
}
}
}
// 保存稀疏数组
File file = new File("C:\\Users\\18147\\Desktop\\map.data");//这里写你创建文件的地址,我是直接在桌面上创建了一个
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter write = new OutputStreamWriter(fos, "UTF-8");
// 输出稀疏数组的形式
System.out.println();
System.out.println("得到的稀疏数组为~~~");
for (int i = 0; i < sparseArr.length; i++) {
System.out.printf("%d\t%d\t%d\t\n", sparseArr[i][0], sparseArr[i][1], sparseArr[i][2]);
if (i == sparseArr.length - 1) {
write.append(sparseArr[i][0] + "," + sparseArr[i][1] + "," + sparseArr[i][2]);
} else {
write.append(sparseArr[i][0] + "," + sparseArr[i][1] + "," + sparseArr[i][2] + ",");
}
}
System.out.println("写入文件中...");
write.close();
fos.close();
System.out.println("打开文件中...");
Desktop.getDesktop().open(file);
System.out.println("------------------------------先读取_map.data");
// 创建 FileReader 对象
FileInputStream fis = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
StringBuffer sb = new StringBuffer();
while (reader.ready()) {
sb.append((char) reader.read());// 转成char加到StringBuffer对象中
}
System.out.println(sb.toString());
reader.close();// 关闭读取流
fis.close();// 关闭输入流,释放系统资源
System.out.println("------------------------------恢复成稀疏数组_sparseArrHf");
System.out.println();
System.out.println("压缩成稀疏数组表现为:");
// 遍历打印稀疏数组
for (int i = 0; i < sparseArr.length; i++) {
// 格式化输出每一行的三列数,并且每打印三个数换行
System.out.printf("%d\t %d\t %d\t", sparseArr[i][0], sparseArr[i][1], sparseArr[i][2]);
System.out.println();
}
// 将稀疏数组转换为二维数组的思路
// 1.读取稀疏数组第一行的值,根据第一行的值来创建原始的二维数组
int[][] chessArr2 = new int[sparseArr[0][0]][sparseArr[0][1]];
// 2.读取后几行的数据填充二维数组
for (int i = 1; i < sparseArr.length; i++) {// 因为是从第二行开始读数的,所以要从i=1开始
chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
}
// 输出原始的二维数组
System.out.println();
System.out.println("打印恢复后的二维数组");
for (int[] row : chessArr2) {
for (int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
}
}
运行结果图: