前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >稀疏数组如何帮助我们节省内存,提升性能

稀疏数组如何帮助我们节省内存,提升性能

作者头像
葡萄城控件
发布2023-11-14 08:17:08
3510
发布2023-11-14 08:17:08
举报
文章被收录于专栏:葡萄城控件技术团队

什么是稀疏矩阵

稀疏矩阵是指矩阵中大部分元素为零的矩阵。在实际应用中,很多矩阵都是稀疏的,比如网络图、文本数据等。由于矩阵中存在大量的零元素,因此稀疏矩阵的存储和计算都具有一定的特殊性。

一般来说,在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵;与之相反,若非0元素数目占大多数时,则称该矩阵为稠密矩阵。下面的矩阵就是一个典型的稀疏矩阵:

优化稀疏矩阵数据存储的方法

1.直接存储为二维矩阵

使用二维矩阵作为电子表格的存储方法具有简单直接的优点,可以避免频繁地创建或删除内存段。然而,需要指出的是,这种方式在存储值时可能会有一些不太高效的方面,因为它会占用大量的存储空间来保存没有实际内容的单元格。

在实际应用中通常使用三元组表示稀疏矩阵:

三元组的表示方法是:对于一个 m×n 的稀疏矩阵 A,我们只存储矩阵中非零元素的信息,具体来说,将每个非零元素的行下标、列下标和值存储下来,得到一个三元组(i,j,Ai,j),其中 i 是行下标,j 是列下标,Ai,jA 中对应位置的值。

以前面举的稀疏矩阵为例,其三元组表示如下:

代码语言:javascript
复制
(1, 4, 6)
(2, 2, 5)
(3, 3, 4)

直接存储为二维矩阵的复杂度:

  • 占用空间:O(N2)
  • 插入数据:需要破坏矩阵。
  • 删除数据:需要破坏矩阵。
  • 搜索数据:O(N2)。
  • 访问数据:O(1)。

N是假设行和列具有相同长度并形成正方形矩阵的行/列数。

2.通过键值对(Map, Dictionary)优化

通过键值对(Map, Dictionary)来优化,主要是利用哈希表的特性来快速查找元素。具体来说,可以将需要查找的元素作为键,将存储这些元素的数据结构作为值,然后将它们存储在一个哈希表中。这样,当需要查找某个元素时,只需要使用该元素作为键,通过哈希表的查找操作即可快速找到对应的值。

在实际应用中,常见的情况包括:

  1. 缓存数据:在需要频繁访问数据的场景中,通过建立一个缓存,将数据存储在一个键值对的数据结构中,可以显著提高数据的访问效率。
  2. 字符串处理:在需要对字符串进行匹配、查找等操作的场景中,可以将字符串作为键,将相应的处理结果作为值,存储在一个键值对的数据结构中,可以大幅提高字符串处理的效率。
  3. 数据库操作:在需要对数据库进行访问的场景中,可以使用键值对数据结构来存储查询结果,避免重复执行查询操作,减轻数据库的负载。

在下图中,将单元格位置和对应的单元格值以键值对的形式进行了存储。

通过键值对(Map, Dictionary)优化稀疏数组的复杂度:

  • 空间:O(N)。
  • 插入:O(1)。
  • 删除:O(1)。
  • 搜索:O(N)。
  • 访问:O(1)。

N为所记录的条目数。

3.通过数组存储方式优化

在稀疏矩阵中,我们可以使用三个不同的数组来存储行索引、列偏移、和其中的值,而不是直接在二维矩阵中存储值。

存储的三个数组:

  1. =>单元格中的值。
  2. 行索引=>单元格的行索引。
  3. 列偏移=>这里每个索引都代表列,并且该数组将行开始的索引值存储在 Row 数组中。

下图为将稀疏数组转化为数组的形式:

稀疏矩阵具体的插入,删除,搜索,访问的代码:

代码语言:javascript
复制
import java.util.HashMap;
import java.util.Map;

class SparseMatrix {
    private int rows;
    private int cols;
    private Map<String, Integer> matrix;

    public SparseMatrix(int rows, int cols) {
        this.rows = rows;
        this.cols = cols;
        this.matrix = new HashMap<>();
    }

    public void insert(int row, int col, int value) {
        if (row < 0 || row >= rows || col < 0 || col >= cols) {
            throw new IndexOutOfBoundsException("Invalid matrix index");
        }
        if (value != 0) {
            String key = row + "," + col;
            matrix.put(key, value);
        }
    }

    public void delete(int row, int col) {
        String key = row + "," + col;
        matrix.remove(key);
    }

    public int search(int row, int col) {
        String key = row + "," + col;
        return matrix.getOrDefault(key, 0);
    }

    public int access(int row, int col) {
        if (row < 0 || row >= rows || col < 0 || col >= cols) {
            throw new IndexOutOfBoundsException("Invalid matrix index");
        }
        String key = row + "," + col;
        return matrix.getOrDefault(key, 0);
    }
}

在上述代码中,定义了一个 SparseMatrix 类来表示稀疏矩阵。在构造函数中,我们传入矩阵的行数和列数,并创建了一个 HashMap 对象 matrix 来存储非零元素。insert 方法用于向矩阵中插入元素,如果插入的值不为零,则将其加入 matrix 中,其中键为字符串形式的 row,col。delete 方法用于删除指定位置的元素,通过 remove 方法从 matrix 中移除对应的键值对。search 方法用于搜索指定位置的元素,通过调用 getOrDefault 方法从 matrix 中获取对应的值,如果不存在则返回默认值 0。access 方法用于访问指定位置的元素,如果超出矩阵边界则抛出异常,通过调用 getOrDefault 方法从 matrix 中获取对应的值。

通过稀疏矩阵存储方式优化的复杂度:

  • 空间:O(N)。
  • 插入:O(N)。
  • 删除:O(N)。
  • 搜索:O(N)。
  • 访问:O(1)。

总结

相较于传统的数组存储或键值对存储,稀疏矩阵存储采用一种基于行索引的数据字典存储方法,这种方法在处理松散布局的表格数据时表现出色。与其他存储方式不同,稀疏矩阵只存储非空数据,无需额外开辟内存空间来存储空数据。这种特殊存储策略使得数据片段化变得容易,可以随时框取整个数据层中的一片数据进行序列化或反序列化。如果在项目开发中需要存储类似结构的数据,使用稀疏矩阵存储方式能够显著提升性能,无论从时间还是空间上都有很大的优势,葡萄城公司的纯前端表格控件——SpreadJS正是借助此功能实现了高性能渲染能力(100 毫秒内加载 10 万行数据)。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-11-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档