我必须在当前项目中使用稀疏向量来处理某些事情。但是,由于我不负责该项目,我不能使用我想要的任何外部库。我只提供STL和OpenCV。
我已经查看了几个stackoverflow已回答的问题,但是当他们专门处理稀疏向量时,他们要么focus on a specific approach,comparison of a limited number of approaches (2) and outside libraries。实施sparse matrix还有一些很好的想法。
我想要的是特别是稀疏矢量(索引总是在1维,数据与此问题无关)。我想要的东西不是自己实现的项目,但可以用于超出示范目的(例如,我希望获得合适的速度而不是太多的内存开销)并且希望重新实现以后用过。我考虑的选项包括:
std::map
存储值(或者制作一个非常简单的包装器,以便在索引零元素时返回默认值)std::vector< std::pair < int , data_type > >
我可以将索引和数据存储在std::pair
元素中这些解决方案中的任何一个对于作为稀疏向量的通用用途是更好/更差吗?我知道每件事的每一种方法都有它起伏不定,但是我们非常赞赏有关选择哪种方法的建议。另外,如果有人认为他有更好的建议,推荐一种我没有考虑的方法将非常受欢迎。
我的具体情况如下:
尽管如此,正如我在原始问题中所写的那样,我想了解通用稀疏矢量实现的建议。
答案 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
将在所有用例(查找/插入/更新)中提供良好的默认性能,并且使用自定义类意味着如果您需要更改为其他实现,则无需更改客户来源,只需重新编译。