一种使用unordered_map表示对称稀疏矩阵的有效方法

时间:2019-02-02 12:53:53

标签: c++ algorithm matrix typedef unordered-map

我正在使用unordered_map容器表示对称的稀疏矩阵。这是因为我不需要计算所有位置,并且可以将坐标用作 key 来进行快速数据检索。我的地图如下:

typedef std::size_t coord1D;
typedef std::pair<coord1D,coord1D> coord2D;
struct pair_hash {
    template <class T1, class T2>
    std::size_t operator() (const std::pair<T1, T2> &pair) const {
        return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
    }
};
typedef std::unordered_map<coord2D, std::shared_ptr<double>, pair_hash> my_map;

问题是,每次定义键值时,由于矩阵的三角形性质,我需要为两个键( eg 。ij和ji对)提供相同的值这代表,所以:

my_map example;
example [std::make_pair(0,1)] = std::make_shared<double> (0.5);
example [std::make_pair(1,0)] = std::make_shared<double> (0.5);

我正在考虑使用便利函数(因为此处不能覆盖operator=)是为了避免代码冗余,但是我也想知道是否有一种更有效的方式来处理此任务。我认为使用的容器是最好的容器(因为不需要unordered_multimap

1 个答案:

答案 0 :(得分:3)

unordered_map的typedef上构建矩阵类型似乎没有提供很好的封装。当然,乍看之下,这似乎提供了非常精简的解决方案。但是最后,operator=的问题是这种构造如何与open/close principle冲突的完美例证。

因此,我的建议是将基础数据结构包装在一个类中以改善封装(为简单起见,我使用double而不是共享指针):

using coord1D = std::size_t;    // time to forget about typedef ? 
using coord2D = std::pair<coord1D,coord1D>;
struct pair_hash {
    template <class T1, class T2>
    std::size_t operator() (const std::pair<T1, T2> &pair) const {
        return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
    }
};
class matrix {
    std::unordered_map<coord2D, double, pair_hash> m; 
public: 
    auto& operator[] (pair<int,int> p) { 
        if (p.first>p.second)
            p = make_pair(p.second, p.first);
        return m[p];
    }
};

在这种情况下,您可以将参数转换为operator[],以便通过设计使矩阵变为三角形,从而避免了冗余代码和冗余存储。

演示:

matrix m;
m[make_pair(1,5)] = 27.2;
cout << m[make_pair(1,5)]<<" "<<m[make_pair(5,1)]<<endl;

Online demo

当然,更好的方法是定义一个通用矩阵,并将其派生为一个专门的三角矩阵,在该矩阵中进行坐标转换。