首页 > 系统相关 >如何写成高性能的代码(三):巧用稀疏矩阵节省内存占用

如何写成高性能的代码(三):巧用稀疏矩阵节省内存占用

时间:2022-11-15 22:00:20浏览次数:41  
标签:存储 表格 单元格 矩阵 稀疏 内存 数据 巧用

稀疏矩阵的概念

一个m×n的矩阵是一个由m行n列元素排列成的矩形阵列。矩阵里的元素可以是数字、符号及其他的类型的元素。

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

如何写成高性能的代码(三):巧用稀疏矩阵节省内存占用_搜索

我们日常使用的电子表格也是一个典型的稀疏矩阵场景,电子表格(SpreadJS, Excel,Google Sheet等等),整体看起来像一个table表格。,

其中列名称依次为A, B, C … …, 行名称依次为1, 2, 3 … …

举例一个比较极端的场景,在A1ZZ2000单元格分别赋值,这样我们就需要一个2000行,26*26+26=702列的矩阵来表示它,这个矩阵是一个明显的稀疏矩阵。

稀疏矩阵的存储方式及优化

直接存储为二维矩阵

直接使用二维矩阵会简单直接地存储整个电子表格,这样你不必每次都创建或删除一段内存。
但这是一种非常暴力的存储值的方法,这种方式下会消耗大量内容来存储毫无内容的单元格。
简单的来看一下它的复杂度:

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

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

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

在这种方法中,只有在单元格有值时,我们才将单元格的值和位置存储在一起,使用HashMap或者Dictionary这些数据结构可以很容易的做到.。

下图我们可以看到,键值对中分别存储了单元格位置和单元格值。

如何写成高性能的代码(三):巧用稀疏矩阵节省内存占用_稀疏矩阵_02

来看一下它的复杂度:

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

N为所记录的条目数。

通过稀疏矩阵存储方式优化

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

存储的三个数组:

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

如何写成高性能的代码(三):巧用稀疏矩阵节省内存占用_搜索_03

稀疏矩阵具体的插入,、删除,、搜索,、访问的代码,大家可以自己来搜索,这方面的资料网上有很多。,这里不一一列举。

和上面一样,来看看这种方式的复杂度:

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

相较于传统的数组存储或是键值对存储,稀疏矩阵存储构建了基于行索引为 Key 的数据字典,在松散布局的表格数据中,稀疏矩阵只会对非空数据进行存储,而不需要对空数据开辟额外的内存空间。使用这种特殊的存储策略,使得数据片段化变得容易,可以随时框取整个数据层中的一片数据,进行序列化或反序列化。如果我们在项目开发中需要存储类似结构的数据,稀疏矩阵这种存储方式,无论从时间还是空间上都能大大的提成性能。

在葡萄城的 SpreadJS ​和 GcExcel 表格组件中,也巧妙的使用了稀疏矩阵这一特性,可以随时替换或恢复整个存储结构中的任何一个级别的节点,以改变引用的方式更高效的地解决表格数据回滚和恢复问题,而这一点也为葡萄城表格组件支持多人在线协同打下了一个良好的基础。

由于底层采用了稀疏矩阵来优化存储,SpreadJS在前端页面中,实现了100W级别数据秒级响应的能力:

如何写成高性能的代码(三):巧用稀疏矩阵节省内存占用_搜索_04

纯前端百万级数据请求、加载、筛选和排序

点击此处可以在线体验:性能演示

同时,结合SpreadJS中使用的Canvas 绘制模型,双缓存画布渲染等专利技术,让SpreadJS的前端性能相比于同类产品遥遥领先。

更多纯前端表格在线demo示例 :https://demo.grapecity.com.cn/spreadjs/gc-sjs-samples/index.html

纯前端表格应用场景:https://www.grapecity.com.cn/developer/spreadjs#scenarios

移动端示例(可扫码体验):http://demo.grapecity.com.cn/spreadjs/mobilesample/


本文是由葡萄城技术开发团队发布,转载请注明出处:葡萄城官网




标签:存储,表格,单元格,矩阵,稀疏,内存,数据,巧用
From: https://blog.51cto.com/powertoolsteam/5854307

相关文章

  • 内存分析及数组的3种初始化
    内存分析Java内存分析:数组的3种初始化静态初始化int[]a={1,2,3};Man[]mans={newMan(1,1),newMan(2,2)};动态初始化int[]a=newint[2];a[0]......
  • 为什么要求内存对齐
    当我们在我们的代码中申明变量时,我们通常是不用考虑也不会去做所谓的内存对齐的,因为这个工作本身是属于编译器去完成的。那我们的变量为什么不按照大小顺序地存放而是非要......
  • C++类的内存结构
     第一种这个类是个空类 sizeof会占用一个字节 newt也是占用一个字节但作为其他类的成员变量可能会占用1-2-4-8字节这个是类的内存对齐导致 第2种这......
  • 分页内存与非分页内存的疑惑
    参考:https://bbs.pediy.com/thread-160200.htm张帆《驱动详解》中讲到:当程序的中断请求级在DISPATCH_LEVEL之上时(包括DISPATCH_LEVEL层),程序只能使用非分页内存,否则将......
  • linux内存介绍
    [yunwei@192~]#freetotalusedfreesharedbuff/cacheavailableMem:323601921512724010232428767304......
  • Java 内存分区之什么是 CCS区 Compressed Class Space 类压缩空间
    https://blog.csdn.net/qq_27093465/article/details/106760961 Java内存分区之什么是CCS区CompressedClassSpace类压缩空间  了解到什么是ccs区,一般都是实际......
  • 70. 爬楼梯 ----- 动态规划、滚动数组(技巧动态规划)、数学方法:特征方程、矩阵快速幂
    假设你正在爬楼梯。需要n 阶你才能到达楼顶。每次你可以爬1或2个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例1:输入:n=2输出:2解释:有两种方法可以爬到楼顶......
  • os::虚拟内存
    概念虚拟内存是程序,或者多个程序执行,内存没有这么大,但是却能执行,就是用到虚拟技术每个程序都有自己的空间,将空间分成多块每一块称为一页或者一个页面,然后通过分页技术映......
  • C温故补缺(十四):内存管理
    内存管理stdlib库中有几个内存管理相关的函数序号函数和描述1void*calloc(intnum,intsize);在内存中动态地分配num个长度为size个字节 的连续空间,并将......
  • dfs::矩阵路径
    ACwing23方法dfs开始以为是dijkstra没想到是dfs学习冲这个题中看出,dfs用的是标记,不一定是visited[],能标记,递归就行代码boolhasPath(vector<vector<char>>&matrix......