不使用外部库的稀疏矢量实现建议

时间:2012-05-29 09:58:29

标签: c++ data-structures sparse-matrix

我必须在当前项目中使用稀疏向量来处理某些事情。但是,由于我不负责该项目,我不能使用我想要的任何外部库。我只提供STL和OpenCV。

我已经查看了几个stackoverflow已回答的问题,但是当他们专门处理稀疏向量时,他们要么focus on a specific approachcomparison of a limited number of approaches (2) and outside libraries。实施sparse matrix还有一些很好的想法。

我想要的是特别是稀疏矢量(索引总是在1维,数据与此问题无关)。我想要的东西不是自己实现的项目,但可以用于超出示范目的(例如,我希望获得合适的速度而不是太多的内存开销)并且希望重新实现以后用过。我考虑的选项包括:

  • 根据我的需要调整SparseMat OpenCV 实施
  • 使用std::map存储值(或者制作一个非常简单的包装器,以便在索引零元素时返回默认值)
  • 使用std::vector< std::pair < int , data_type > >我可以将索引和数据存储在std::pair元素中

这些解决方案中的任何一个对于作为稀疏向量的通用用途是更好/更差吗?我知道每件事的每一种方法都有它起伏不定,但是我们非常赞赏有关选择哪种方法的建议。另外,如果有人认为他有更好的建议,推荐一种我没有考虑的方法将非常受欢迎。


我的具体情况如下:

  • 矢量很可能在创建后不会被修改(现在我认为没有必要这样做,但我不能保证100%它不会出现)
  • 预计最常见的操作是两个这样的向量的点积(因此,或多或少以线性顺序方式访问元素)
  • 我现在可以预见的唯一查询是(可能)检查天气某个元素是否为零元素
  • 预计会有大约500个非零元素
  • 简而言之,大多数时候稀疏矢量将被用作矢量(多维点)的数学概念,而不需要分别检查每个坐标

尽管如此,正如我在原始问题中所写的那样,我想了解通用稀疏矢量实现的建议。

2 个答案:

答案 0 :(得分:5)

我相信std::map会给你最好的结果。 SpareseMat,我不知道,但在您提到的其他两种方法中,std::map会给您O(log(n))查找以及O(log(n))插入和删除。但是vector需要搜索其所有数据(因此它有O(n)个查找)。它已插入O(1),但O(n)已被删除。我的猜测是你会有很多查找,所以很可能std::map对你来说更好。

根据您的应用程序,您可能希望在初始创建结构时使用vector方法,然后在开始使用它时将其转换为map以获得两全其美(但是通常情况并非如此,例如在您有重复索引的情况下。)

除了hash 应该为您提供O(1)所有内容,但实际上可能不会,O(log(n))的查找是您可以期待的最佳内容。您可以提出一个可以二进制搜索的向量,或者基于通过比较搜索数据的任何其他方法,但最终它们都是O(log(n))所以您不妨使用easy-already -done std::map


更新:根据您问题的更新,这表明矢量很可能在创建后不会被修改最常见的操作预计将是点积,我建议如下:

首先,使用你自己建议的对矢量。在创建过程中,只需push_back即可获得O(1)性能。 1 之后,您可以对向量进行排序。点积非常简单 2

int dot = 0;
unsigned int index_v1 = 0, index_v2 = 0;
while (index_v1 < v1.size() && index_v2 < v2.size())
    if (v1[index_v1].first == v2[index_v2].first)
        dot += v1[index_v1++].second * v2[index_v2++].second;
    else if (v1[index_v1].first < v2[index_v2].first)
        ++index_v1;
    else
        ++index_v2;

检查某个元素是否为零元素将是一个简单的二进制搜索,检查是否可以找到该元素(O(log(n))性能)。

鉴于您将使用此结构作为一个点,我相信保持它是一个向量会更好。您可能希望稍后进行跨产品或其他几何操作。

关于你可能需要在vector 中不时插入的事实,那么你必须将它插入到位(因此矢量仍然排序)。性能将是O(n),但由于它不经常发生,因此不应成为问题。

1 除非您有数百万这些向量,O(1) O(log(n))n ~= 500不应该有任何明显的差异。

2 您当然也可以使用map并使用迭代器按索引顺序执行点积。如果std::map使用a threaded tree来访问O(1)中的下一个节点,则效果会相同。

答案 1 :(得分:2)

<强> KISS

从最简单的解决方案开始,即将std::map<size_t, YourData>包装到特定的稀疏向量结构中:

template <typename V>
class SparseVector {
public:

private:
    std::map<size_t, V> specificValues;
    V defaultValue;
};

map将在所有用例(查找/插入/更新)中提供良好的默认性能,并且使用自定义类意味着如果您需要更改为其他实现,则无需更改客户来源,只需重新编译。