如何实现 sparse_vector 类
Posted
技术标签:
【中文标题】如何实现 sparse_vector 类【英文标题】:how to implement a sparse_vector class 【发布时间】:2010-05-11 06:14:43 【问题描述】:我正在实现一个模板化的 sparse_vector 类。它就像一个向量,但它只存储与其默认构造值不同的元素。
因此,sparse_vector 将为值不是 T() 的所有索引存储 惰性排序 索引值对。
我的实现基于数字库中现有的稀疏向量——尽管我的也将处理非数字类型 T。我看了boost::numeric::ublas::coordinate_vector
和eigen::SparseVector
。
两个商店:
size_t* indices_; // a dynamic array
T* values_; // a dynamic array
int size_;
int capacity_;
他们为什么不简单地使用
vector<pair<size_t, T>> data_;
我的主要问题是这两个系统的优缺点是什么,最终哪个更好?
pair 的向量为您管理 size_ 和 capacity_,并简化了随附的迭代器类;它也有一个内存块而不是两个,因此它会导致一半的重新分配,并且可能具有更好的引用局部性。
另一种解决方案可能会更快地搜索,因为在搜索期间缓存行仅填充索引数据。如果 T 是 8 字节类型,可能还有一些对齐优势?
在我看来,成对向量是更好的解决方案,但两个容器都选择了另一个解决方案。为什么?
【问题讨论】:
我认为map
+ 大小/容量会比任何数组/向量选项更好。 o.0
首先,在 pair<size_t, T>
中有一个未初始化的 T 将与 pair 的 ctors 和 dtor 混淆(并且基本上是不可行的)。马上,您就需要自己的专用实用程序类(例如 boost::optional)。
@Dav:boost 有另一种使用地图的稀疏向量类型。对于具有许多条目的向量,在实践中会慢一些。不过这是一个很好的解决方案。 @Roger Pate:您存储的 T 都已初始化。
@Dav:澄清了向量已排序(在进行查找时,但不确定插入...),因此它与查找的 map 一样快(第一个除外)——并且会产生一小部分缓存未命中数
【参考方案1】:
将索引放在单独的列表中会使它们的查找速度更快 - 正如您所建议的那样,它会更有效地使用缓存,尤其是在 T 很大的情况下。
如果您想实现自己的,为什么不直接使用std::map
(或std::unordered_map
)?密钥会更大,但实现时间将接近于零!
【讨论】:
【参考方案2】:实际上,他们似乎重新发明了***(可以这么说)。
我个人会根据您的需要考虑 2 个库:
Loki,对于Loki::AssocVector
-> 通过vector
实现的地图接口(这是您希望做的)
Boost.Iterator,用于其iterator_adaptor
类。通过 Composition 实现新容器变得非常容易。
作为评论,我会注意到您可能希望与T()
不同的值更通用一点,因为这将T
强制为DefaultConstructible。您可以提供一个采用T const&
的构造函数。在编写通用容器时,最好尽量减少必要的要求(只要不影响性能)。
另外,我要提醒您,使用vector
进行存储的想法对于少量值非常有用,但您可能希望将底层容器更改为经典的map
或unordered_map
,如果值的数量增加。这可能值得分析/计时。请注意,STL 通过容器适配器(如 stack
)提供了此功能,尽管它可能会使实现稍微困难一些。
玩得开心。
【讨论】:
感谢您指出 iterator_adaptor -- 不知道。以上是关于如何实现 sparse_vector 类的主要内容,如果未能解决你的问题,请参考以下文章