我正在使用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
。
答案 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;
当然,更好的方法是定义一个通用矩阵,并将其派生为一个专门的三角矩阵,在该矩阵中进行坐标转换。