稀疏矩阵的压缩与还原(Java实现)

简介: 稀疏矩阵的压缩与还原(Java实现)

稀疏矩阵的压缩与还原(Java实现)


1.稀疏矩阵的概念


在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵,如:


20190829090621613.png

2.稀疏矩阵的压缩


如果要把一个含有如此多0元素的稀疏矩阵存储到计算机中,这些没有意义的0同样地会消耗掉计算机的内存,那么这势必造成计算机内存的浪费。那么,对于稀疏矩阵的存储,我们应该如何去处理呢?下面介绍一个例子:


例: 现在要模拟一个11*11的五子棋棋盘的存档和续局。棋盘上有黑、白两种棋子,分别用1、2来表示,没有棋子的地方,则用0来表示。假设这个棋盘是只有3颗棋子,2颗白棋子,1颗黑棋子,则该棋盘抽象出来,就是一个稀疏矩阵,其中非0元素只有3个,分别是1,2,2。现在,不想下棋了,那么要保存这个棋盘,也就是保存这个稀疏矩阵。

图解思路:


棋盘上的状态如图


20190829092602266.png

我们从图所得到的信息:棋盘矩阵是11 * 11的,有3颗棋子

黑子所在的位置是矩阵的第3行第3列,值是1

白子所在的位置是矩阵的第6行第2列、第4行第5列,值都为2

转化成数组的存储,就是:

黑子所在的位置是矩阵的第2行第2列,值是1

白子所在的位置是矩阵的第5行第1列、第3行第4列,值都为2(因为数组的下标是从0开始的)

那么,我们可以将上面的信息抽象成一个新的二维数组:


20190829095016131.png


这样就实现了稀疏矩阵的压缩

下面是代码实现:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class SparseArray {
    public static void main(String[] args) throws IOException {
        //创建一个原始的二维数组11*11
        //0:表示无棋子,1表示黑子,2表示白子
        int[][] chessArr1=new int[11][11];
        chessArr1[2][2]=1;
        chessArr1[5][1]=2;
        chessArr1[3][4]=2;
        //输出原始的二维数组
        System.out.println("原始的二维数组:");
        for (int[] row:chessArr1){
            for (int data:row){
                System.out.printf("%d\t",data);
            }
            System.out.println();//每打印一行就换一行
        }
        //将二维数组 转 稀疏数组
        //1.先遍历二维数组,得到非0数据的个数
        int count=0;
        for(int[] row:chessArr1){
            for (int data:row){
                if (data!=0){
                    count++;
                }
            }
        }
        System.out.println("非0的元素个数为:"+count);
        //2.创建稀疏数组
        int[][] sparseArr=new int[count+1][3];
        //3.给稀疏数组赋值
        sparseArr[0][0]=11;
        sparseArr[0][1]=11;
        sparseArr[0][2]=count;
        //4.遍历二维数组,将非0的值存放到sparseArr中
        int row=1;//用于记录是第几个非0数据
        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 11; j++) {
                if (chessArr1[i][j]!=0){
                    sparseArr[row][0]=i;
                    sparseArr[row][1]=j;
                    sparseArr[row][2]=chessArr1[i][j];
                    row++;
                }
            }
        }
        //6.输出稀疏数组
        System.out.println("得到的稀疏数组为:");
        for (int[] row1:sparseArr){
            for (int data:row1){
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }
        //7.将稀疏数组写入到文件中
        FileWriter writer=null;
        try {
            writer=new FileWriter(new File("E:\\Java项目\\Java数据结构\\src\\cn\\Day01\\Files\\data.txt"));
            int count1=0;//用于控制换行
            for (int i = 0; i < sparseArr.length; i++) {
                for (int j = 0; j < sparseArr[i].length; j++) {
                    writer.write(sparseArr[i][j]+"\t");
                    count1++;
                    if (count1%3==0){
                        writer.write("\n");
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (writer!=null) {
                writer.close();
            }
        }


输出结果如下:

控制台输出结果:


20190829094755786.png

由于需求是棋盘存档,显然要把压缩后的数组保存到文件中,那么上面代码得到的data.txt文件内容如下:

20190829095239564.png


棋盘存档成功!


3.稀疏矩阵的还原


还原的话就很简单了,利用压缩后的数组的第0行信息来构建新的二维数组(11 * 11),然后读取第一行以后的信息,把非0元素的行、列和值对应地赋值到新二维数组就可以了。


整个需求的完整代码实现如下:


package cn.Day01.demo2;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class SparseArray {
            public static void main(String[] args) throws IOException {
                //创建一个原始的二维数组11*11
                //0:表示无棋子,1表示黑子,2表示白子
                int[][] chessArr1=new int[11][11];
                chessArr1[2][2]=1;
                chessArr1[5][1]=2;
                chessArr1[3][4]=2;
                //输出原始的二维数组
                System.out.println("原始的二维数组:");
                for (int[] row:chessArr1){
                    for (int data:row){
                        System.out.printf("%d\t",data);
                    }
                    System.out.println();//每打印一行就换一行
                }
                //将二维数组 转 稀疏数组
                //1.先遍历二维数组,得到非0数据的个数
                int count=0;
                for(int[] row:chessArr1){
                    for (int data:row){
                        if (data!=0){
                            count++;
                        }
                    }
                }
                System.out.println("非0的元素个数为:"+count);
                //2.创建稀疏数组
                int[][] sparseArr=new int[count+1][3];
                //3.给稀疏数组赋值
                sparseArr[0][0]=11;
                sparseArr[0][1]=11;
                sparseArr[0][2]=count;
                //4.遍历二维数组,将非0的值存放到sparseArr中
                int row=1;//用于记录是第几个非0数据
                for (int i = 0; i < 11; i++) {
                    for (int j = 0; j < 11; j++) {
                        if (chessArr1[i][j]!=0){
                            sparseArr[row][0]=i;
                            sparseArr[row][1]=j;
                            sparseArr[row][2]=chessArr1[i][j];
                            row++;
                        }
                    }
                }
                //6.输出稀疏数组
                System.out.println("得到的稀疏数组为:");
                for (int[] row1:sparseArr){
                    for (int data:row1){
                        System.out.printf("%d\t",data);
                    }
                    System.out.println();
                }
                //7.将稀疏数组写入到文件中
                FileWriter writer=null;
                try {
                    writer=new FileWriter(new File("E:\\Java项目\\Java数据结构\\src\\cn\\Day01\\Files\\data.txt"));
                    int count1=0;//用于控制换行
                    for (int i = 0; i < sparseArr.length; i++) {
                        for (int j = 0; j < sparseArr[i].length; j++) {
                            writer.write(sparseArr[i][j]+"\t");
                            count1++;
                            if (count1%3==0){
                                writer.write("\n");
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    if (writer!=null) {
                        writer.close();
                    }
                }
        //根据稀疏矩阵来还原二维数组
        //0.将稀疏数组从文件中读取出来:
        /**
         *
         */
        FileReader reader=new FileReader(new File("E:\\Java项目\\Java数据结构\\src\\cn\\Day01\\Files\\data.txt"));
        BufferedReader bfreader=new BufferedReader(reader);
        String temp;
        String[] temps=null;
        int lineArr=0;
        while ((temp= bfreader.readLine())!=null){
            temps=temp.split("\t");
            for (int i=0;i<temps.length;i++){
                sparseArr[lineArr][i]=Integer.parseInt(temps[i]);
            }
            lineArr++;
        }
        System.out.println("还原后的稀疏矩阵为:");
        for (int i = 0; i < sparseArr.length; i++) {
            for (int j = 0; j < sparseArr[i].length; j++) {
                System.out.printf("%d\t",sparseArr[i][j]);
            }
            System.out.println();
        }
        //1.先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
        int[][] chessArr2=new int[sparseArr[0][0]][sparseArr[0][1]];
        //2.遍历稀疏矩阵,给二维数组赋值
        for(int i=1;i<sparseArr.length;i++){
                chessArr2[sparseArr[i][0]][sparseArr[i][1]]=sparseArr[i][2];
        }
        //3.输出原二维数组
        System.out.println("还原后的数组为:");
        for (int i = 0; i < chessArr2.length; i++) {
            for (int j = 0; j < chessArr2[i].length; j++) {
                System.out.printf("%d\t",chessArr2[i][j]);
            }
            System.out.println();
        }
    }
}

4.总结


目前在跟着尚硅谷的韩顺平老师学习图解数据结构和算法(Java版),刚学完第一个知识点,受益匪浅,故作此篇,与各位学习交流!

相关文章
|
1月前
|
安全 Java Android开发
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
50 5
|
2月前
|
安全 Java Android开发
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
101 2
|
2月前
|
算法 Java
Java 压缩文件
在Java中压缩文件是一个常见的需求,通常可以通过使用Java自带的`java.util.zip`包来实现。这个包提供了`ZipOutputStream`类来创建ZIP格式的压缩文件。以下是一个简单的示例,展示了如何将多个文件压缩到一个ZIP文件中。 ### 示例:将多个文件压缩到一个ZIP文件中 ```java import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class ZipFilesExample { public static vo
|
3月前
|
Java 大数据 测试技术
Java对象头压缩---- 永久为Java应用“降本增效”
本文介绍了一下OpenJDK的最新技术,对象头压缩,来大幅优化Java对象的内存占用。
|
3月前
|
Java
Java SpringBoot 7z 压缩、解压
Java SpringBoot 7z 压缩、解压
70 1
|
4月前
|
Java 运维
开发与运维技术问题之ava对象头压缩技术支持所有的Java垃圾回收器如何解决
开发与运维技术问题之ava对象头压缩技术支持所有的Java垃圾回收器如何解决
33 1
|
3月前
|
存储 安全 算法
Java中防止压缩炸弹的技术分享
【8月更文挑战第17天】在软件开发和数据处理的日常工作中,我们经常会遇到各种压缩文件。然而,一种被称为“压缩炸弹”的恶意文件却给开发者带来了不小的困扰。压缩炸弹通过特殊设计的压缩算法,使得极小的文件在解压后能膨胀到异常巨大的体积,从而消耗大量系统资源甚至导致系统崩溃。本文将围绕“如何在Java中防止压缩炸弹”这一主题,分享一些实用的技术干货。
117 0
时间轮-Java实现篇
在前面的文章《[时间轮-理论篇](https://developer.aliyun.com/article/910513)》讲了时间轮的一些理论知识,然后根据理论知识。我们自己来实现一个简单的时间轮。
|
11天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
7天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
27 9