[Data structure]稀疏数组

news2024/10/5 21:25:41

⭐作者介绍:大二本科网络工程专业在读,持续学习Java,努力输出优质文章
⭐作者主页:@逐梦苍穹
⭐所属专栏:数据结构。数据结构专栏主要是在讲解原理的基础上拿Java实现,有时候有C/C++代码。
⭐如果觉得文章写的不错,欢迎点个关注一键三连😉有写的不好的地方也欢迎指正,一同进步😁

目录

  • 1、简介
  • 2、简单例子
  • 3、优缺点
  • 4、应用场景
  • 5、代码实现
    • 5.1、简述步骤
    • 5.2、Java实现
      • 5.2.1、无IO流
      • 5.2.2、结合IO流

1、简介

  稀疏数组是一种压缩数据的方式,它在处理大规模二维数组时,可以用较小的存储空间来表示大部分元素都为默认值或者重复值的数组。在这种情况下,使用稀疏数组可以显著减少存储空间的占用。
  稀疏数组的一般形式是一个三元组 [i, j, value],其中 ij 表示数组中某个元素的行和列,value 表示该元素的值。通常情况下,我们会用一个二维数组来表示原始数组,并将稀疏数组存储在一个一维数组中。

2、简单例子

在这里插入图片描述

比如有一个原始数组是10 X 10的,其中数据不为零的索引为:[1,2],[2,3],[3,4],其余数据为0,
如下所示:
  在这里插入图片描述

创建一个稀疏数组,首行记录原始数组的行数、列数、非零的有效值个数,从第二行开始,记录有效值的行索引、列索引、有效值,
如下:
  在这里插入图片描述

3、优缺点

使用稀疏数组的优点:

  1. 空间利用率高:稀疏数组只存储非默认值的元素信息,可以大大减少存储空间的占用。
  2. 方便进行压缩和解压缩:稀疏数组可以方便地进行压缩和解压缩操作,对于大型稀疏矩阵的存储和传输非常有用。
  3. 可以提高运算效率:稀疏数组在进行运算时,可以只对非默认值元素进行处理,避免对所有元素进行无效操作,从而提高运算效率。

使用稀疏数组的缺点:

  1. 降低了数组的访问速度:由于稀疏数组中非默认值元素的位置信息需要额外存储,访问这些元素的速度相对较慢,特别是在大规模稀疏矩阵中。
  2. 需要进行额外的处理:使用稀疏数组需要额外处理元素的位置信息,这会增加代码的复杂性和维护成本。
  3. 不适用于密集矩阵:对于密集矩阵,使用稀疏数组存储反而会增加存储空间的占用。

综上所述,稀疏数组适用于大部分元素都为默认值或重复值的情况,可以显著减少存储空间的占用,但同时也需要特别注意其访问速度和代码复杂性等问题。

4、应用场景

稀疏数组主要应用于以下场景:

  1. 图像处理:在处理图像时,由于图像中大多数像素值是相同的或者为默认值,因此使用稀疏数组可以大大减少存储空间。
  2. 文本处理:在文本处理中,使用稀疏数组可以节省存储空间,特别是对于文本中大量重复的字符或单词。
  3. 矩阵计算:在矩阵计算中,由于大多数矩阵元素都是零,因此使用稀疏数组可以显著提高计算效率。
  4. 数据库系统:在数据库系统中,由于大多数数据都是默认值或者重复数据,因此使用稀疏数组可以节省存储空间和提高查询效率。
  5. 网络传输:在网络传输中,使用稀疏数组可以减少传输数据的大小,从而提高传输速度。

总的来说,稀疏数组适用于大部分元素都为默认值或重复值的情况,可以显著减少存储空间的占用,并且在某些场景下可以提高计算效率和传输速度。

5、代码实现

5.1、简述步骤

二维数组 转 稀疏数组的思路:

  1. 遍历 原始的二维数组,得到有效数据的个数
  2. 根据 有效数据的个数 就可以创建 稀疏数组
  3. 将二维数组的有效数据数据存入到 稀疏数组

稀疏数组转原始的二维数组的思路

  1. 先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
  2. 在读取稀疏数组后几行的数据,并赋给 原始的二维数组 即可.

下面用代码详细实现

5.2、Java实现

5.2.1、无IO流

这里重点先了解如何实现稀疏数组和稀疏数组向原始数组的转换:
①创建原始数组
  在这里插入图片描述

②创建稀疏数组

/**
  稀疏数组
 */
public static int[][] arrayToSparseArr(int[][] array) {
    //1、获取有效数据,即不为零的数据
    int count = 0;
    for (int[] row : array) {
        for (int data : row) {
            if (data != 0) {
                count++;
            }
        }
    }

    //创建稀疏数组
    int[][] sparseArray = new int[count + 1][3];
    //设置稀疏数组首行的值
    //row
    sparseArray[0][0] = 10;
    //row_data
    sparseArray[0][1] = 10;
    //value
    sparseArray[0][2] = count;
    //遍历存入有效数据,定义一个索引值
    int index = 1;
    for (int i = 0; i < array.length; i++) {
        for (int j = 0; j < array[i].length; j++) {
            if (array[i][j] != 0) {
                sparseArray[index][0] = i;
                sparseArray[index][1] = j;
                sparseArray[index][2] = array[i][j];
                index++;
            }
        }
    }

    for (int[] row : sparseArray) {
        for (int data : row) {
            System.out.printf("%d\t", data);
        }
        System.out.println();
    }
    return sparseArray;
}

③稀疏数组转原始数组
在这里插入图片描述

完整代码:

package sparseArray;

/**
 * @author 逐梦苍穹
 * @date 2023/4/12 23:14
 */
public class SparseArray {
    public static void main(String[] args) {
        //创建原始数组
        int[][] array = new int[10][10];
        array[1][2] = 1;
        array[2][3] = 2;
        array[3][4] = 3;
        System.out.println("原始数组:");
        for (int[] row : array) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }

        //稀疏数组
        System.out.println("稀疏数组:");
        int[][] sparseArray = arrayToSparseArr(array);

        System.out.println("稀疏数组->原始数组:");
        //回到原始数组
        for (int[] row : sparseArrToArray(sparseArray)) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
    }

    public static int[][] arrayToSparseArr(int[][] array) {
        //稀疏数组
        //1、获取有效数据,即不为零的数据
        int count = 0;
        for (int[] row : array) {
            for (int data : row) {
                if (data != 0) {
                    count++;
                }
            }
        }

        //创建稀疏数组
        int[][] sparseArray = new int[count + 1][3];
        //设置稀疏数组首行的值
        //row
        sparseArray[0][0] = 10;
        //row_data
        sparseArray[0][1] = 10;
        //value
        sparseArray[0][2] = count;
        //遍历存入有效数据,定义一个索引值
        int index = 1;
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                if (array[i][j] != 0) {
                    sparseArray[index][0] = i;
                    sparseArray[index][1] = j;
                    sparseArray[index][2] = array[i][j];
                    index++;
                }
            }
        }

        for (int[] row : sparseArray) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
        return sparseArray;
    }

    public static int[][] sparseArrToArray(int[][] sparseArr) {
        int[][] array = new int[sparseArr[0][0]][sparseArr[0][1]];
        for (int i = 1; i < sparseArr.length; i++) {
            array[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }
        return array;
    }
}

5.2.2、结合IO流

先看一下代码整体思路总览:
在这里插入图片描述

下面重点说IO读写:
①IO输出流,把稀疏数组输出到文件。

思路是:

  1. 先创建文件对象,判断该对象是否存在
  2. 获取字符缓冲输出流,在流里面传入转换流,在转换流里面传入文件输出流,传入参数为文件路径和指定字符集编码。(如果不需要指定字符编码,直接获取字符缓冲流即可,像这样:
    在这里插入图片描述
    )
  3. 遍历内存中的稀疏数组,调用输出流的write方法往文件中写入数据。

输出流部分的代码如下:
在这里插入图片描述

②IO输入流,把文件中的稀疏数组数据输入到内存。

思路是:

  1. 获取字符缓冲输入流,在流里面传入转换流,在转换流里面传入文件输入流,传入参数为文件路径和指定字符集编码。(如果不需要指定字符编码,直接获取字符缓冲流即可,像这样:
    在这里插入图片描述
    )
  2. 遍历内存中的稀疏数组,调用输入流的readLine方法按行读取文件中的数据

输入流部分的代码如下:
在这里插入图片描述

结合IO流的完整代码如下:

package sparseArray;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * @author 逐梦苍穹
 * @date 2023/4/13 10:00
 */
public class SparseArrayIo {
    /**
     * main方法中创建原始数组和调用各种静态方法
     */
    public static void main(String[] args) throws Exception {
        //创建原始数组
        int[][] array = new int[10][10];
        array[1][2] = 1;
        array[2][3] = 2;
        array[3][4] = 3;
        System.out.println("原始数组:");
        for (int[] row : array) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }

        //稀疏数组
        System.out.println("稀疏数组:");
        int[][] sparseArray = arrayToSparseArr(array);

        System.out.println("稀疏数组->原始数组:");
        //回到原始数组
        for (int[] row : sparseArrToArray(sparseArray)) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }

        //稀疏数组写入文件
        String filePath = "src/sparseArray/sparseArray.txt";
        boolean flag = writeSparseArrayToFile(sparseArray, filePath);

        //稀疏数组数据文件写入内存
        if (flag) {
            //从文件写入内存
            System.out.println("从文件写入内存:");
            writeFileToRam(filePath);
        }
    }

    /**
     * 稀疏数组
     */
    public static int[][] arrayToSparseArr(int[][] array) {
        //1、获取有效数据,即不为零的数据
        int count = 0;
        for (int[] row : array) {
            for (int data : row) {
                if (data != 0) {
                    count++;
                }
            }
        }

        //创建稀疏数组
        int[][] sparseArray = new int[count + 1][3];
        //设置稀疏数组首行的值
        //row
        sparseArray[0][0] = 10;
        //row_data
        sparseArray[0][1] = 10;
        //value
        sparseArray[0][2] = count;
        //遍历存入有效数据,定义一个索引值
        int index = 1;
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                if (array[i][j] != 0) {
                    sparseArray[index][0] = i;
                    sparseArray[index][1] = j;
                    sparseArray[index][2] = array[i][j];
                    index++;
                }
            }
        }

        for (int[] row : sparseArray) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
        return sparseArray;
    }

    /**
     * 稀疏数组转原始数组
     */
    public static int[][] sparseArrToArray(int[][] sparseArr) {
        int[][] array = new int[sparseArr[0][0]][sparseArr[0][1]];
        for (int i = 1; i < sparseArr.length; i++) {
            array[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }
        return array;
    }

    /**
     * 稀疏数组写入磁盘
     */
    public static boolean writeSparseArrayToFile(int[][] sparseArray, String filePath) throws Exception {
        boolean flag = false;
        //得到了稀疏数组,此时要把它存入磁盘
        File file = new File(filePath);

        if (!file.exists()) {
            flag = file.createNewFile();
        }
        if (flag) {
            try (
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath), StandardCharsets.UTF_8))
            ) {
                for (int i = 0; i < sparseArray.length; i++) {
                    for (int j = 0; j < sparseArray[i].length; j++) {
                        bw.write(sparseArray[i][j] + "\t");
                    }
                    if (i == sparseArray.length - 1) {
                        break;
                    } else {
                        bw.write("\n");
                    }
                }
            } catch (Exception e) {
                System.out.println(e);
                return false;
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * 磁盘文件写入内存
     */
    public static void writeFileToRam(String filePath) throws Exception {
        try (
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8))
        ) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/418509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

清肠化湿颗粒通过激活NLRP6信号和调节Th17/Treg平衡来改善DSS诱导的结肠炎

百趣代谢组学分享-文章标题&#xff1a;Qing-Chang-Hua-Shi granule ameliorates DSS-induced colitis by activating NLRP6 signaling and regulating Th17/Treg balance 代谢组学分享-发表期刊&#xff1a;Phytomedicine 代谢组学分享-影响因子&#xff1a;6.656 代谢组学…

python 对数函数

在 Python中&#xff0c;除了对数函数&#xff0c;还有其他的一些函数&#xff0c;例如&#xff1a; 这是一个在 python中用来计算两个整数之间的关系的函数。如果两个整数的值不同&#xff0c;则它们之间的关系是&#xff1a; 其中aa^2bb^2cc^2。下面是计算两个整数之间的关系…

微信小程序开发(学习记录1.0)

首先&#xff0c;把遇到的问题贴出来&#xff0c;主要是这个解决问题的思路&#xff0c;供大家参考。 现在的问题是将下面的导航栏做出来&#xff0c;但是在自己做的时候 遇到的问题 在app.json文件中输入tarBar&#xff0c;就会生成模板代码&#xff0c;默认会生成一个list的模…

【面试题】calc()计算函数的作用和理解

前言 最近项目中遇到calc()方法不生效问题&#xff0c;本着究其所以然的想法&#xff0c;彻底查了一下calc的方法及使用&#xff0c;还有为什么项目中使用不生效的问题&#xff0c;最后总结出此文&#xff0c;解决方法放在结尾了 cale()是什么 calc是英文单词calculate的缩写…

低功耗技术——流水线设计(加法器和乘法器)

文章目录前言一、流水线1、16bit加法器2、无符号4bit乘法器3、编写一个4bit乘法器模块&#xff0c;并例化该乘法器求解c12*a5*b二、降低FPGA功耗1、静态功耗2、动态功耗前言 2023.3.31 今天学习降低功耗的一些方法 一、流水线 电路最高工作频率&#xff1a;取决于最长的组合逻…

高扇出的危害及优化

高扇出有哪些危害&#xff1f; 危害1&#xff1a;驱动能力下降&#xff0c;时序紧张 扇出过高也就是也就意味了负载电容过大&#xff0c;电路原理基础告诉咱们&#xff0c;负载电容越大&#xff0c;充放电速度越慢&#xff0c;电平跳变所需要的时间增加&#xff0c;即驱动能力…

「SAP ABAP」OPEN SQL(八)【WHERE语句大全】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后端的开发语言A…

MySQL主从复制、读写分离(MayCat2)实现数据同步

文章目录1.MySQL主从复制原理。2.实现MySQL主从复制&#xff08;一主两从&#xff09;。3.基于MySQL一主两从配置&#xff0c;完成MySQL读写分离配置。&#xff08;MyCat2&#xff09;1.MySQL主从复制原理。 MySQL主从复制是一个异步的复制过程&#xff0c;底层是基于Mysql数据…

AI编程助手 Kodezi : 记录、分享一个 VS code 插件

目录0. 概述1. 安装 / 功能介绍1.1 安装1.2 功能介绍1.2.1 Debug1.2.2 代码优化1.2.3 代码转换1.2.4 逐行注释1.2.5 多行注释1.2.6 生成文档1.2.7 生成代码2. KodeziChat 聊天机器人2.1 聊天机器人功能介绍2.2 如何使用 KodeziChat &#xff1f;3. Kodezi 版本介绍3.1 免费版3.…

【2023年第十一届泰迪杯数据挖掘挑战赛】C题:泰迪内推平台招聘与求职双向推荐系统构建 建模及python代码详解 问题三

相关链接 【2023年第十一届泰迪杯数据挖掘挑战赛】C题泰迪内推平台招聘与求职双向推荐系统构建 建模及python代码详解 问题一 【2023年第十一届泰迪杯数据挖掘挑战赛】C题泰迪内推平台招聘与求职双向推荐系统构建 建模及python代码详解 问题二 【2023年第十一届泰迪杯数据挖…

【软件应用】TamperMonkey同步操作

不废话&#xff0c;记录一些关键点 要设置同步&#xff0c;先得打开高级设置模式 众所周知&#xff0c;这里可以设置同步&#xff0c;建议设置为WebDAV同步&#xff0c;这样通用性更强 至于选择啥网盘就看自己的需求了&#xff0c;支持WebDAV的网盘还是很多的&#xff0c;甚…

数据库设计案例

一个专辑可以包含多个曲目&#xff0c;一个曲目只能属于一个专辑 一对多 一个专辑可以包含多条短评&#xff0c;一条短语只能属于一个专辑 一对多 一个用户可以包含多条短评&#xff0c;一个短评只能属于一个用户 一对多 一个专辑可以属于多个用户&#xff0c;一个用户…

04-vue3侦听器

文章目录1.watch1.侦听数据源类型2.demo2.watchEffect函数3.watch vs. watchEffect1.watch 计算属性允许我们声明性地计算衍生值。然而在有些情况下&#xff0c;我们需要在状态变化时执行一些“副作用”&#xff1a;例如更改 DOM&#xff0c;或是根据异步操作的结果去修改另一…

熬大夜~ 阿里P8架构师总结微服务设计企业架构转型之道笔记

前言 本文涉及两个方面的知识体系&#xff0c;即企业架构知识体系和软件架构知识体系。 企业架构和软件架构虽然都与IT相关&#xff0c;但其知识体系是完全不同的两个领域。一般而言&#xff0c;搞企业架构的人士不明白软件架构的细节和实现&#xff0c;而从事软件架构的架构…

如何评价一款RTK差分基站的性能?

RTK是Real-Time Kinematic(实时动态)的缩写&#xff0c;是一种利用载波相位观测进行实时动态相对定位的技术&#xff0c;它能够实时提供测站点在指定坐标系中的三维定位结果&#xff0c;并达到厘米级精度。国内有时也将利用RTK技术为卫星定位设备提供厘米级修正服务的RTK基站简…

114. 二叉树展开为链表 Python

文章目录一、题目描述示例 1示例 2示例 3二、代码三、解题思路一、题目描述 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终…

基于jsp的公交查询系统源码数据库论文

目录 摘 要 1 Abstract 1 1 绪论 1 1.1 选题背景 1 1.2 国内外发展状况 1 1.3 选题的目的 1 1.4 研究手段及意义 1 2相关技术简介 3 2.1Jsp技术介绍 3 2.2 MyEclipse简介 4 2.3 数据库技术 4 2.3.1 数据库的体系结构 4 2.3.2 数据库管理系统&#xff08;D…

(十七)排序算法-基数排序

1 基本介绍 1.1 概述 &#xff08;1&#xff09;基数排序&#xff08;radix sort&#xff09;属于“分配式排序”&#xff0c;顾名思义&#xff0c;它是通过键值的各个位的值&#xff0c;将要排序的元素分配至某些“桶”中&#xff0c;达到排序的作用。 &#xff08;2&#x…

Denoising Diffusion Probabilistic Model,DDPM阅读笔记——(一)

Denoising Diffusion Probabilistic Model一、写在前面二、相关数学知识简介二、生成模型简介&#xff1a;三、变分自编码器概述&#xff08;VAE&#xff09;一、写在前面 人工智能生成内容&#xff08;AI Generated Content&#xff0c;AIGC&#xff09;近年来成为了非常前沿…

2023最新面试题-Java-2

基础语法 1. Java有哪些数据类型 定义&#xff1a;Java语言是强类型语言&#xff0c;对于每一种数据都定义了明确的具体的数据类型&#xff0c;在内存中分配了不同 大小的内存空间。 细化的数据类型就是占用空间的基本元素。分类&#xff1a;基本数据类型 数值型 整数类型…