如何实现 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_vectoreigen::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&lt;size_t, T&gt; 中有一个未初始化的 T 将与 pair 的 ctors 和 dtor 混淆(并且基本上是不可行的)。马上,您就需要自己的专用实用程序类(例如 boost::optional)。 @Dav:boost 有另一种使用地图的稀疏向量类型。对于具有许多条目的向量,在实践中会慢一些。不过这是一个很好的解决方案。 @Roger Pate:您存储的 T 都已初始化。 @Dav:澄清了向量已排序(在进行查找时,但不确定插入...),因此它与查找的 map 一样快(第一个除外)——并且会产生一小部分缓存未命中数 【参考方案1】:

将索引放在单独的列表中会使它们的查找速度更快 - 正如您所建议的那样,它会更有效地使用缓存,尤其是在 T 很大的情况下。

如果您想实现自己的,为什么不直接使用std::map(或std::unordered_map)?密钥会更大,但实现时间将接近于零!

【讨论】:

【参考方案2】:

实际上,他们似乎重新发明了***(可以这么说)。

我个人会根据您的需要考虑 2 个库:

Lo​​ki,对于Loki::AssocVector -> 通过vector 实现的地图接口(这是您希望做的) Boost.Iterator,用于其iterator_adaptor 类。通过 Composition 实现新容器变得非常容易。

作为评论,我会注意到您可能希望与T() 不同的值更通用一点,因为这将T 强制为DefaultConstructible。您可以提供一个采用T const&amp; 的构造函数。在编写通用容器时,最好尽量减少必要的要求(只要不影响性能)。

另外,我要提醒您,使用vector 进行存储的想法对于少量值非常有用,但您可能希望将底层容器更改为经典的mapunordered_map,如果值的数量增加。这可能值得分析/计时。请注意,STL 通过容器适配器(如 stack)提供了此功能,尽管它可能会使实现稍微困难一些。

玩得开心。

【讨论】:

感谢您指出 iterator_adaptor -- 不知道。

以上是关于如何实现 sparse_vector 类的主要内容,如果未能解决你的问题,请参考以下文章

JAVA框架如何实现调用接口的实现类的呢?例实现httpsessionlistener接口类被调。

IDEA 如何查找抽象类的实现

一个类没有接口,如何实现Spring管理

在类中如何实现类的嵌套

类加载器如何实现类隔离

一个接口有多个实现类时,调用接口时,如何判定调用的哪个实现类?