C++ 更高效的稀疏矩阵元素存取器

C++ 更高效的稀疏矩阵元素存取器,c++,stl,map,sparse-matrix,C++,Stl,Map,Sparse Matrix,我与成员一起编写了一个小型稀疏矩阵类: std::map<int,std::map<int,double> > sm; std::map-sm; 下面的方法是我用来访问矩阵元素的函数,如果不能通过迭代器访问的话: double matrix::operator()(int r,int c) const { std::map<int,std::map<int,double> >::const_iterator i = sm.find(r)

我与成员一起编写了一个小型稀疏矩阵类:

std::map<int,std::map<int,double> > sm;
std::map-sm;
下面的方法是我用来访问矩阵元素的函数,如果不能通过迭代器访问的话:

double matrix::operator()(int r,int c) const
{
    std::map<int,std::map<int,double> >::const_iterator i = sm.find(r);
    if(i==sm.end()) { return 0.0; }
    std::map<int,double>::const_iterator j = i->second.find(c);
    if(j==i->second.end()) { return 0.0; }
    return j->second;
}
double matrix::operator()(int r,int c)const
{
std::map::const_迭代器i=sm.find(r);
如果(i==sm.end()){return 0.0;}
std::map::const_迭代器j=i->second.find(c);
如果(j==i->second.end()){return 0.0;}
返回j->second;
}

这个函数仍然需要经常调用。有人知道如何改进这个功能吗?非常感谢。

如果您想编写自己的代码而不是使用库,那么此更改可能会显著提高性能:

std::map<std::pair<int,int>, double> sm;
我认为,如果使用Boost.MultiIndex,您可以通过使用适当的函子调用equal_range来实现上述功能

一切:

for(auto& cell : sm)
{ ... }

要在列上迭代,需要分别搜索每个单元格。请注意,您的数据结构也不提供此操作。

您可能会讨厌此操作,但对于矩阵的以下行(用于显示的较小行):

1059000

您可以有一个位数组(本例中为8位),其中每个位都被设置或清除,以反映矩阵中该位置是否存在非零或零

然后,您只需将非零数存储在一个规则数组中,就像:

{ 1, 5, 9 }
和二进制标志

0x98//二进制1001 1000

要遍历矩阵行,只需使用位操作循环遍历位数组:

while (! /* not at the end of the bit array */ ) {
    f = get_next_from_bit_array();  // This is just bitwise shift and bitwise & 
    if (!f) {
       val = 0;
    } else {
       val = compressed_row[i];
       i++;
    }
    do_action(val);
}
我的代码只是演示,不是C++,但是我希望你能理解这个想法。 使用位数组将允许您检查稀疏行的更小内存区域,这意味着更少的内存访问和更好的缓存位置


如果您使用的矩阵非常稀疏,那么您也可以将其扩展到其他维度(具有稀疏的行数组),但整行为空的可能性很低。

谢谢。不过我有一个问题:在你建议的地图中,行和列的迭代不是更复杂吗?@litro:在第一个地图中不是。要对一行进行迭代,只需调用该行开头和结尾处的equal_range,并在该行开头和结尾处获得一对迭代器。这个方法和你的方法都不能提供一种简单的方法来迭代列。我已经在我的类型上使用无序的映射进行了测试,结果更糟。但是关于我的访问器:这已经是最优的了还是这个特定的访问器可以改进?@litro:您的访问器对于您的数据结构来说是最优的。您介意给出一个迭代所有行的示例吗?我似乎有一个愚蠢的例子。这是一个有趣的方法,但与原始方法相比,它的缩放特性较差。理想情况下,如果矩阵的大小增加,但非零元素的数量保持不变,则稀疏矩阵的存储不会增加。他的方法确实有这个特点,但你的方法没有。这确实可以适当地扩展,因为只有位数组随着新的0元素的维度增长而增长,而且这种增长非常小。我是在阅读了对另一个建议的评论后选择这个建议的,该建议提到了迭代矩阵的重要性。还有其他几种方法可以更好地实现这一点,它们适用于不同级别的稀疏性——我想到了使用(索引,值)的列表。
{ 1, 5, 9 }
while (! /* not at the end of the bit array */ ) {
    f = get_next_from_bit_array();  // This is just bitwise shift and bitwise & 
    if (!f) {
       val = 0;
    } else {
       val = compressed_row[i];
       i++;
    }
    do_action(val);
}