C++中的稀疏数组
Posted
技术标签:
【中文标题】C++中的稀疏数组【英文标题】:Sparse array in C++ 【发布时间】:2014-01-23 14:16:25 【问题描述】:我需要一个类似向量的容器,具有整数索引,但省略了一些索引。那么在 C++ 中表示这种稀疏数组的常用方法是什么? 我有一种直觉,std::map 主要用于此类目的。但是对于通常不添加新项目的容器来说,它的速度相当慢。你有什么建议?
UPD:不是很“稀疏”。也许大约 5%。项目主要在初始化步骤期间添加(之后不经常添加)。但是访问很频繁(如果不是很重要,显然我不会开始这个话题)。
【问题讨论】:
尝试使用 boost 或 C++11 的无序映射。 “稀疏”有多稀疏?百分比?如果经常期望在两者之间存储附加值,则某些技术可能不合适。您是否需要按索引顺序频繁访问/迭代? 解释它有多慢。 boost flat map 是 map 的更快版本,除了插入速度非常慢 (O (n)) 所以你的使用模式必须是 fill map,use map,而不是:fill map,use,add,use , 添加, 删除, 使用... 这似乎是XY Problem。问题显然是性能要求,您假设实现这些要求的方法是使用稀疏数组。 【参考方案1】:是的,地图通常是正确的方法。
我建议使用 C++11 unordered_map
(基于哈希表)来获得闪电般快速的查找:这几乎是没有连续递增键的最佳选择。
【讨论】:
虽然可能一开始就提出了错误的问题,但我看不出unordered_map
将如何满足对 sparse 容器的假定需求。在被索引之前,不能保证unordered_map
已经分配了任意未分配的索引。
@JohnDibling:你为什么需要它?只需将unordered_map
的size_t
设置为所需的映射类型。有什么问题?
@John Dibling 但这就是稀疏数组的全部意义:在为数组元素 i 赋值之前,没有为索引 i 分配任何东西。
@laune:不,这与稀疏数组相反。稀疏阵列就像一个只有 10% 已满的磁盘。 90% 的空间仍然被分配,从某种意义上说,磁盘实际上并没有增长,但它充满了未初始化的垃圾。
@John Dibling wikipedia, "sparse array": "一个简单的数组实现可能会为整个数组分配空间,但是在非默认值很少的情况下,这种实现是低效的。”具有 N 个元素的向量(如数学)始终具有 N 个元素,但稀疏数组的实现不应分配所有无用的存储空间。我不确定您所说的“稀疏容器”是什么意思,但是拥有一个包含大量未使用空间的 container 并不是实现稀疏向量的明智选择。【参考方案2】:
也许像
std::vector<boost::optional<your_type>>
对你来说已经足够了。
【讨论】:
可能不是一个好主意。不过,可能是正确的方法。取决于某些事情。 如果对象很大,它应该可以正常工作 - 但如果对象很小并且索引很大,则不会。 这取决于其他一些事情。例如他是否需要快速知道是否填充了特定索引?【参考方案3】:项目主要是在初始化步骤中添加的(之后并不经常添加)。但访问频繁
在这种情况下,boost::container::flat_map 对您来说是一个不错的选择。它基本上只是一个排序的向量。优点(从网站上偷来的):
比标准关联容器更快的查找 迭代速度比标准关联容器快得多 小对象的内存消耗更少(如果使用了 shrink_to_fit,对于大对象) 提高缓存性能(数据存储在连续内存中)一个潜在的缺点:
最坏的线性时间插入和线性时间删除即使最坏的情况发生在插入或删除过程中(移动底层向量的元素),它仍然没有那么糟糕,这要归功于(1)缓存的良好使用,(2)底层元素的重定位可能是矢量化(矢量指令)。鉴于您的使用模式,您必须在您的应用程序中尝试它以查看插入/删除是否存在问题。
如果flat_map
不适合你,我会试试std::unordered_map
。
【讨论】:
以上是关于C++中的稀疏数组的主要内容,如果未能解决你的问题,请参考以下文章